$.Deferred:如何检测每个Promise何时被执行

IT技术 javascript jquery asynchronous promise jquery-deferred
2021-01-24 07:30:28

我有许多需要完成的异步任务,所以我使用了 Promise。

我需要检测每一个Promise何时被执行(解决和拒绝)。在那之前我不能继续执行。

我正在使用这样的东西:

$.when(promise1, promise2, ...).always();

但是这段代码是错误的,因为该when方法具有惰性求值,并且一旦其中一个Promise失败它就会返回。因此,always只要其中一个Promise失败回调也会运行。

我想在编码一个解决办法,但这种使用情况是如此普遍,也许有人已经做它已经,或者也许有这样做只使用jQuery的(如果不是,这将是很好添加的,甚至一种方式Promise.whenNonLazyPromise.when(promise1, promise2, ..., false)在未来。

这可能吗?

3个回答

更复杂的诺言库有一个allSettled()类似的功能QPromise.settle类似蓝鸟

在 jQuery 中,您也可以自己实现这样的函数并$用它扩展命名空间,但这只有在您经常需要并优化性能时才有必要。

一个更简单的解决方案是为您正在等待的每个Promise创建一个新的Promise,并在底层Promise被拒绝时实现它们。然后你可以$.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.

好的,我刚刚理解了其中的null论点then它让已解决的Promise按原样返回。但这$.Deferred绝对需要括号。
2021-03-14 07:30:28
如果你想为 a 添加代码$.settle(),这里有一个:stackoverflow.com/a/35820459/271351
2021-03-26 07:30:28
我想我明白了,但它$.Deferred是一个函数,你可能需要它$.Deferred()此外,我认为您需要将成功回调传递给与p.then错误回调相同的回调。
2021-04-07 07:30:28

铁匠铺,

首先让我们假设您的Promise在一个数组中。

var promises = [....];

您似乎想要的是.when()应用于这些Promise的一些转换,这样任何被拒绝的Promise都会被转换为已解决,同时对已经解决的Promise是透明的。

所需的操作可以非常简洁地写成如下:

$.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()来区分已解决和已拒绝的Promise,并做出相应的响应。

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()回调的每个参数,其对应的Promise最初是被解决还是被拒绝。这就是您将拒绝转换为解决方案所要付出的代价。但是,您可能能够从解决/拒绝原始Promise的参数中检测原始状态。

这是一个有趣的属性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/

.always() 只需要一个回调,你为什么要通过两个?
2021-03-20 07:30:28
是的,这是基本的想法。我正在做类似的事情:我为每个延迟创建一个延迟的包装器,然后在包含的延迟解决或被拒绝时解析包装器。最后$.when在所有包装器上应用常规我仍然需要弄清楚如何将已解决的参数传递回主延迟($.whenPromise,如果已解决,将接收每个Promise的单个参数列表)。我想用我的whenNonLazy方法做同样的事情
2021-04-04 07:30:28