Javascript-执行长承诺时过多的递归
作者:互联网
我有很长的异步函数序列要顺序执行.因此,我使用了Promise创建Promise队列.不幸的是,在Linux上的Firefox 25.0.1上,我收到了太多的递归JavaScript错误.它可以在Mac上的同一Firefox版本上正常运行,也可以在chrome中运行.但是我需要它在任何地方都可以工作,包括Linux.您能否提出更好的executePromiseQueueSync函数实现?
//-----------------------------------------------------------------------------------------
function executePromiseQueueSync(queue){
var seed = $.Deferred();
var acc = seed;
for (var i = 0; i < queue.length; ++i )
{
var promise = queue[i];
acc = acc.then(promise.funct.apply(null, promise.argmnt));
}
seed.resolve();
return acc;
}
//-----------------------------------------------------------------------------------------
function someTask(){
var dfd = new jQuery.Deferred();
dfd.notify();
dfd.resolve();
return dfd.promise();
}
//-----------------------------------------------------------------------------------------
$(function(){
var promisesQueue = []
for(var i = 0; i < 200; ++i){
promisesQueue.push({funct:someTask, argmnt:[]});
}
executePromiseQueueSync(promisesQueue).then(function(){alert('done!');});
});
//-----------------------------------------------------------------------------------------
JSF中间示例:http://jsfiddle.net/C2YN4/4/
到目前为止,我所拥有的(并且我非常乐于接受其他主张和更正):
function executePromiseQueueSync(queue){
if (queue.length > TRESHOLD){
var i,j;
var shortQueue = []
for (i=0,j=queue.length; i<j; i+=TRESHOLD) {
temparray = queue.slice(i, i+TRESHOLD);
shortQueue.push({funct:executePromiseQueueSync, argmnt:[temparray]});
}
return executePromiseQueueSync(shortQueue);
}
var seed = $.Deferred();
var acc = seed;
for (var i = 0; i < queue.length; ++i )
{
var promise = queue[i];
acc = acc.then(promise.funct.apply(null, promise.argmnt));
}
seed.resolve();
return acc;
}
因此,基本思想是制作一个承诺树而不是承诺链.这样,我们就不会深入堆栈.
例如:http://jsfiddle.net/fMBJK/1/
解决方法:
您可以使用jQuery.when〜,尽管传入200多个参数可能有些疯狂:
小提琴的代码
jQuery的JavaScript
var resolves = [];
function log(msg){
$('#log').append('<div><small>' + msg + '</small></div>');
}
function someTask(i){
var dfd = new $.Deferred();
log('created task '+i);
resolves.push(function(){
log('resolved task '+i);
dfd.resolve();
});
return dfd.promise();
}
$(function(){
$('#resolve1').click(function(){
for ( var i=0; i<resolves.length; i++ ) {
resolves[i]();
}
});
$('#resolve2').click(function(){
for ( var i=0; i<resolves.length; i++ ) {
if ( i == 5 ) continue;
resolves[i]();
}
});
$('#resolve3').click(function(){
resolves[5]();
});
var i, queue = []; for(i=0; i<200; ++i){ queue.push(someTask(i)); }
(jQuery.when.apply(jQuery, queue))
.done(function(){
log('all resolved!');
alert('all resolved!');
})
;
});
此示例的标记
<button id="resolve1">Resolve all</button>
<button id="resolve2">Resolve (all but one)</button>
<button id="resolve3">Resolve (the remaining one)</button>
<div id="log"></div>
此示例的CSS
#log {
border: 1px solid black;
padding: 10px;
width: 400px;
height: 200px;
overflow: auto;
}
说明
上面的许多代码只是为了说明,关键点是:
var i, queue = []; for(i=0; i<200; ++i){ queue.push(someTask(i)); }
(jQuery.when.apply(jQuery, queue))
.done(function(){
log('all resolved!');
alert('all resolved!');
})
;
上面的代码生成了一个Promise对象数组,然后使用apply将它们传递给jQuery.when,然后当它们全部完成后,它会处理创建正确的结构以触发完成的回调.那就是如果您想要这种行为.如果您想要一个系统来等待每个promise对象按顺序解析,那么在触发下一个任务之前,您将需要一些不同的东西.
更新资料
在顺序执行任务方面,您需要使用其他方法,例如:
function log(msg){
$('#log').append('<div><small>' + msg + '</small></div>');
}
function someTask(i){
var dfd = new $.Deferred();
log(':: created task '+i);
setTimeout(function(){
log(':: resolved task '+i);
dfd.resolve();
},50);
return dfd.promise();
}
$(function(){
var Queue;
Queue = function( items ){
this.items = items.slice(0);
this.promise = $.Deferred();
};
Queue.prototype.next = function(){
log(':: next task triggered');
var q = this;
q.lastItem = q.items.shift();
if ( q.lastItem ) {
q.lastPromise = q.lastItem.func.apply( null, q.lastItem.args );
q.lastPromise.then(function(){
/// include a setTimeout 0 to avoid possible stack/recursion errors.
setTimeout(function(){
q.next();
},0);
});
}
else {
/// we are finished
q.promise.resolve();
}
};
Queue.prototype.run = function(){
this.next();
};
var i, items = []; for(i=0; i<200; ++i){
items.push({ func: someTask, args:[i] });
}
var q = new Queue( items );
q.promise.done(function(){
log(':: done!');
alert('Done!');
});
q.run();
});
这将构建一个定制的Queue对象,该对象跟踪承诺列表,并在第一个成功后触发下一个.但是,此代码显然需要错误处理.
更新x2
每个承诺都不能依赖进度,因为在任何时候都只有一个被触发.您可以将自己的通知调用添加到整个$.Deferred()对象.
var Queue;
Queue = function( items ){
this.items = items.slice(0);
this.promise = $.Deferred();
this.count = 0;
};
Queue.prototype.next = function(){
log(':: next task triggered');
var q = this;
q.lastItem = q.items.shift();
if ( q.lastItem ) {
q.lastPromise = q.lastItem.func.apply( null, q.lastItem.args );
q.lastPromise.then(function(){
q.promise.notify(q.count++);
q.next();
});
}
else {
q.promise.resolve();
}
};
Queue.prototype.run = function(){
this.next();
};
var q = new Queue( items );
q.promise
.done(function(){log(':: done!');})
.progress(function(p){log('::progress ' + p);})
;
q.run();
标签:promise,jquery-deferred,javascript,algorithm,recursion 来源: https://codeday.me/bug/20191122/2059726.html