gpt4 book ai didi

Javascript - 执行长链 promise 时递归过多

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:14:37 25 4
gpt4 key购买 nike

我有一长串要按顺序执行的异步函数。所以我使用 promises 来创建 promise 队列。不幸的是,在 Linux 上的 Firefox 25.0.1 上,我遇到了 too much recursion 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!');});
});

//-----------------------------------------------------------------------------------------

JSFiddle 示例: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;
}

所以基本的想法是做一个promise树而不是promise链。这样我们就不会深入堆栈。

示例:http://jsfiddle.net/fMBJK/1/

最佳答案

您可以使用 jQuery.when ~ 尽管传递超过 200 个参数可能有点疯狂:

http://jsfiddle.net/6j6em/1/

fiddle 的代码

带有 jQ​​uery 的 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>
&nbsp;&nbsp;
<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 然后处理创建正确的结构以触发 done 全部完成后回调。那就是如果你想要这种行为。如果您想要一个系统在触发下一个任务之前等待每个 promise 对象按顺序解析,您将需要一些不同的东西。


更新

就按顺序触发任务而言,您需要一种不同的方法,如下所示:

http://jsfiddle.net/6j6em/2/

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 对象,用于跟踪 promise 列表,并在第一个成功后触发下一个。然而这段代码显然需要错误处理。


更新 x2

您不能依赖于每个 promise 的进展,因为在任何时候只有一个被触发。但是,您可以将自己的通知调用添加到整个 $.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();

关于Javascript - 执行长链 promise 时递归过多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20267354/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com