$.延迟:如何检测每个承诺何时执行
$.Deferred: How to detect when every promise has been executed
我有许多异步任务需要完成,所以我正在使用 promises。
我需要检测每个承诺何时被执行(已解决和拒绝(。在那之前,我绝不能继续执行。
我使用了这样的东西:
$.when(promise1, promise2, ...).always();
但是这段代码是错误的,因为 when
方法具有延迟计算,并且一旦其中一个承诺失败,它就会返回。因此,一旦其中一个承诺失败,always
回调也会立即运行。
我正在考虑编写一种解决方法,但是这个用例非常普遍,也许有人已经这样做了,或者甚至有一种方法可以仅使用jQuery来做到这一点(如果没有,将来最好添加一个Promise.whenNonLazy
或Promise.when(promise1, promise2, ..., false)
。
这可能吗?
更复杂的 promise 库具有像 Q
这样的allSettled()
函数或像 Bluebird 这样的Promise.settle
函数。
在 jQuery 中,您也可以自己实现这样的函数,并使用它扩展$
命名空间,但这只有在您经常需要它并且性能优化时才是必需的。
一个更简单的解决方案是为您正在等待的每个承诺创建一个新的承诺,即使潜在的承诺被拒绝,也要履行它们。然后,您可以毫无问题地对它们使用$.when()
。总之:
// using Underscore's .invoke() method:
$.when.apply(null, _.invoke(promises, "then", null, $.when)).done(…)
更稳定:
$.when.apply($, $.map(promises, function(p) {
return p.then(null, function() {
return $.Deferred().resolveWith(this, arguments);
});
})).then(…);
您可以稍微更改then
回调,以区分最终done
中已实现和拒绝的结果。
Smithy,
首先,让我们假设你的承诺在一个数组中。
var promises = [....];
你似乎想要的.when()
应用于这些承诺的某种转换,这样任何被拒绝的承诺都会转换为已解决的承诺,同时对已经解决的承诺是透明的。
所需的操作可以非常简洁地编写如下:
$.when.apply(null, $.map(promises, resolvize)).done(...);
//or, if further filtering by .then() is required ...
$.when.apply(null, $.map(promises, resolvize)).then(...);
其中resolvize
是转换机制。
那么resolvize()
应该是什么样子呢?让我们利用.then()
的特点来区分已解决的承诺和被拒绝的承诺,并做出相应的回应。
function resolvize(promise) {
//Note: null allows a resolved promise to pass straight through unmolested;
return promise.then(null, function() {
return $.Deferred().resolve.apply(null, arguments).promise();
});
}
未经测试
通过在某些外部作用域中的resolvize
,它可以在需要时用于$.when.apply($.map(promises, resolvize))
表达式中。这很可能是足够的,而无需使用新方法扩展jQuery。
无论转换是如何实现的,你最终都会遇到一个潜在的问题;即知道.done()
回调的每个参数,其相应的承诺最初是被解决还是被拒绝。这就是您将拒绝转换为解决方案所付出的代价。但是,您可以从解决/拒绝原始承诺的参数中检测原始状态。
这是always
的一个有趣的属性 - 我没想到会有这种行为。
我想您可以使用主的顶级延迟来监视主要延迟的状态,只有在主要延迟全部解决或拒绝后才能解决。像这样:
//set up master deferred, to observe the states of the sub-deferreds
var master_dfd = new $.Deferred;
master_dfd.done(function() { alert('done'); });
//set up sub-deferreds
var dfds = [new $.Deferred, new $.Deferred, new $.Deferred];
var cb = function() {
if (dfds.filter(function(dfd) {
return /resolved|rejected/.test(dfd.state());
}).length == dfds.length)
master_dfd.resolve();
};
dfds.forEach(function(dfd) { dfd.always(cb); });
//resolve or reject sub-deferreds. Master deferred resolves only once
//all are resolved or rejected
dfds[0].resolve();
dfds[1].reject();
dfds[2].resolve();
小提琴:http://jsfiddle.net/Wtxfy/3/
- Bluebird中承诺链数组的串行执行
- 执行一系列 Javascript 承诺一个接一个地解决
- 控制承诺执行顺序
- 如何按顺序执行承诺数组
- 无法执行链式承诺
- 循环超出范围,不执行承诺链
- 如何将 $http.put 封装到一个函数中,该函数执行某些操作,然后返回通过或失败的承诺
- 在猫鼬中创建承诺时,不会调用执行器
- 嵌套承诺执行不同步
- nodeJS中的承诺/承诺中的回调/执行顺序是不对的
- 两个捕获的承诺/块声明都没有执行
- 从数组中按顺序执行一堆 WinJS 承诺
- Javascript Jquery在外部样式表更改/重新加载承诺方式后执行代码
- $.延迟:如何检测每个承诺何时执行
- 无论承诺是否履行,如何执行相同的操作
- 链式jQuery承诺提前执行
- 承诺链不使用 Q 承诺库按顺序执行
- AngularJs 单元测试 - 模拟承诺不执行“然后”
- 如何使用本机 JavaScript 承诺执行延迟模式
- 链接承诺执行两个操作