【问题标题】:Continue of failure of jQuery Deferred chainjQuery Deferred 链继续失败
【发布时间】:2015-10-20 21:08:40
【问题描述】:

我正在 jQuery 中执行一系列顺序 AJAX 调用,使用与 Deferred 链接的常用方法。第一次调用返回一个值列表,随后的调用是使用这些返回的列表条目进行的。在返回列表的第一个调用之后,后续调用可以按任何顺序进行,但必须一次调用一个。所以这就是我使用的:

$.when(callWebService()).then(
function (data) {
    var looper = $.Deferred().resolve(),
        myList = JSON.parse(data);
    for (var i in myList) {
        (function (i) {
            looper = looper.then(function () { // Success
                return callWebService();
            }, 
            function (jqXHR, textStatus, errorThrown) { // Failure
                if (checkIfContinuable(errorThrown) == true)
                    continueChain();
                else
                    failWithTerribleError();
            });
        })(i);
    }
});

事实证明,随后的调用有时可能会失败,但我仍然想做剩下的调用。在我的清单中,这就是这个小小的创造性伪代码的目的:

if (checkIfContinuable(errorThrown) == true)
    continueChain();
else
    failWithTerribleError();

我到底该如何实现 continueChain 呢?似乎任何延迟的失败都会导致链的其余部分也失败。相反,我想记录错误并继续列表的其余部分。

【问题讨论】:

  • continueChainfailWithTerribleError 到底是做什么的?
  • @CobusKruger 尝试使用.always()
  • @JosephtheDreamer 他们是占位符。当实现 failWithTerribleError 时,如果错误不可继续,无论是否涉及记录错误、显示警报或其他任何事情,都会做任何需要做的事情。 continueChain 是我要问的问题 - 我希望完成下一个 Web 服务调用,就好像从来没有失败一样。

标签: javascript jquery jquery-deferred deferred


【解决方案1】:

有了Promises/A+,就这么简单

promise.then(…, function(err) {
    if (checkIfContinuable(err))
        return valueToConinueWith;
    else
        throw new TerribleError(err);
})

不幸的是,jQuery is still not Promises/A+ compliant,并转发旧值(结果或错误) - 除非您从回调中返回 jQuery Deferred。这与rejecting from the success handler 的工作方式相同:

jDeferred.then(…, function(err) {
    if (checkIfContinuable(err))
        return $.Deferred().resolve(valueToConinueWith);
    else
        return $.Deferred().reject(new TerribleError(err));
})

【讨论】:

  • 您知道使用.fail() 方法是否有类似的解决方案?我根本不需要并行成功处理程序(您有...),但似乎这个答案只在使用then 的2 或3 个参数形式时才有效。我将此作为一个单独的问题提出here
【解决方案2】:

从 jQuery 承诺链中的错误中恢复比使用 Promises/A+ 实现更冗长,后者自然会在 .catch 或 .then 的错误处理程序中捕获错误。您必须抛出/重新抛出才能传播错误状态。

jQuery 以相反的方式工作。 .then 的错误处理程序(.catch 不存在)自然会传播错误状态。要模拟“catch”,您必须返回一个已解决的承诺,并且链将沿着其成功路径前进。

从您要基于一系列异步调用的项目数组开始,使用Array.prototype.reduce() 很方便。

function getWebServiceResults() {
    return callWebService().then(function(data) {
        var myList;

        // This is genuine Javascript try/catch, in case JSON.parse() throws.
        try {
            myList = JSON.parse(data);
        }
        catch (error) {
            return $.Deferred().reject(error).promise();//must return a promise because that's what the caller expects, whatever happens.
        }

        //Now use `myList.reduce()` to build a promise chain from the array `myList` and the items it contains.
        var promise = myList.reduce(function(promise, item) {
            return promise.then(function(arr) {
                return callWebService(item).then(function(result) {
                    arr.push(result);
                    return arr;
                }, function(jqXHR, textStatus, errorThrown) {
                    if(checkIfContinuable(errorThrown)) {
                        return $.when(arr); // return a resolved jQuery promise to put promise chain back on the success path.
                    } else {
                        return new Error(textStatus);//Although the error state will be naturally propagated, it's generally better to pass on a single js Error object rather than the three-part jqXHR, textStatus, errorThrown set.
                    }
                });
            });
        }, $.when([])) // starter promise for the reduction, resolved with an empty array

        // At this point, `promise` is a promise of an array of results.

        return promise.then(null, failWithTerribleError);
    });
}

注意事项:

  • 假设有一个整体函数包装器function getWebServiceResults() {...}
  • 假定callWebService() 接受item - 即myList 的每个元素的内容。
  • 要完成它的工作,checkIfContinuable() 必须至少接受一个参数。它假定接受errorThrown,但可能同样接受 jqXHR 或 textStatus。

【讨论】:

    猜你喜欢
    • 2017-08-06
    • 2016-03-22
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多