【问题标题】:jQuery: execute array of functions sequentially (both deferreds and non-deferreds)jQuery:按顺序执行函数数组(延迟和非延迟)
【发布时间】:2014-09-15 20:31:34
【问题描述】:

我对使用 Promises 还很陌生,很难理解 jQuery deferreds。

我目前拥有的是我在某个时间点执行的一组函数:

while (queue.length) {
    (queue.shift())();   
}

问题在于,其中一些函数是异步的,但我需要它们一个接一个地运行。

所以队列中的一些函数返回一个延迟(例如通过 jQuery.ajax()),而一些只是普通函数。我想知道如何按顺序+顺序执行它们(仅在前一个函数完成时执行下一个函数)。

我想也许 jQuery.when 会是我正在寻找的东西,但我不知道如何准确地找到它,我只是想出了这个:

var deferred = jQuery.Deferred();
    while (queue.length > 0) {
       deferred.done().then(queue.shift());
    }

【问题讨论】:

  • 如果有异步函数..那么这些函数必须返回一个promise或者需要支持一个回调机制......只有这样你才能做到
  • 异步函数将返回 Promise,但其他函数不会

标签: jquery promise jquery-deferred


【解决方案1】:

非常精明,jQuery.when 您正在寻找的东西。它接受一个 Promise 或一个普通的 non-thenable 并返回一个超过该值的 Promise。但是,由于您在这里有函数而不是值,所以这并不是真正需要的,因为无论如何这是.then 的行为。

var queue = [syncFunction, syncFunc2, returnsPromiseAsync];

var d = $.Deferred().resolve();
while (queue.length > 0) {
   d = d.then(queue.shift()); // you don't need the `.done`
}

(fiddle)

或者,您可以减少;

var res = queue.reduce(function(prev,cur){ // chain to res later to hook on done
    return prev.then(cur);
}, $.Deferred().resolve());

如果你有更多的代码在下面做一些事情,因为队列中的函数可能同步或异步运行(或者一些同步然后我们点击异步),为了避免混乱,你可能希望确保函数始终运行异步。您可以通过将初始 Deferred 上的 resolve 包装在 setTimeout 中轻松做到这一点:

var p = $.Deferred();
var res = queue.reduce(function(prev,cur){ // chain to res later to hook on done
    return prev.then(cur);
}, p);
setTimeout(p.resolve.bind(p), 0);

现在该进程在超时发生之前不会启动,并且在此之后的任何代码肯定会在队列中的第一个函数之前运行。在我看来,这与 jQuery 承诺的语义不一致(因为 they are inconsistent about sync vs. async callbacks),但您可能想要一致性。

如果您需要知道进程何时完成,只需在res 上使用.then 处理程序:

res.then(function() {
    // All functions have now completed
});

对于这些情况,这里有一个简单的包装函数,可以同时完成这两种情况:

function clearQueue(q) {
    var p = $.Deferred();
    setTimeout(p.resolve.bind(p), 0);

    return q.reduce(function(prev,cur){ 
        return prev.then(cur);
    }, p);
}

使用示例(fiddle):

clearQueue(queue).then(function() {
    console.log("All done");
});
console.log("This runs before any queued function starts");

【讨论】:

  • 现在很漂亮。 :-)
  • @Roamer-1888:在当前的实现中似乎是这样;不过,我没有看到它记录在案,你呢?但是随着函数在基于 Promise 的代码中传递的方式,看起来他们不太可能改变它(实现)......
  • 我当然从正式的 jQuery 文档中了解到 .resolve 和 .reject 的“可分离性”,正如他们所说的那样。我再也找不到原文了,但记得那是jQuery.Deferred() 页面的早期版本。但是,如果没有实际记录,至少在 learn.jQuery.com 的Deferred examples 中承认此功能。查找诸如.then( defer.resolve, defer.reject )setTimeout( defer.resolve, ...)image.onerror = defer.reject 之类的短语。
猜你喜欢
  • 1970-01-01
  • 2013-11-19
  • 2016-12-01
  • 2013-04-29
  • 2013-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多