【问题标题】:multiple ajax request $.when on jqueryjquery上的多个ajax请求$ .when
【发布时间】:2017-01-31 01:59:23
【问题描述】:

在 jquery 上使用 $.when 进行延迟 ajax 有一些缺点。成功处理 ajax 调用真是太好了。但是,如果一个失败,您将无法获得另一个请求的其他数据。

例如

var ajax1Success = function() { 返回 $.ajax(...); }; var ajax2Success = function() { 返回 $.ajax(...); }; var ajax3BoundtoFail = function() { 返回 $.ajax(...); }; $.when(ajax1Succes(), ajax2Success(), ajax3BoundtoFail()).done(function(a1, a2, a3) { // 都好 }).失败(函数(){ // 不好... ajax3 注定会失败 });

任何好的解决方案如何从成功的ajax请求中获取其他数据?

【问题讨论】:

    标签: jquery ajax jquery-deferred


    【解决方案1】:

    $.when() 具有“快速失败”设计。这意味着第一个失败的承诺会导致$.when() 拒绝,而您只会得到拒绝信息。来自 jQuery 文档:

    只要所有的 Deferred 解决,或拒绝 master Deferred,只要其中一个 延期被拒绝

    但是,您可以使用不同类型的函数来监控您的一组承诺。这种类型的功能通常称为“结算”,您可以在其中等待所有承诺结算,然后从所有承诺中获取结果,无论它们是解决还是拒绝。

    这是我过去使用的 jQuery promies 的一个实现,您可以像这样使用:

    $.settle([ajax1Succes(), ajax2Success(), ajax3BoundtoFail()]).then(function(results) {
        // results is an array of PromiseInspection Objects
        // for each of them, you can see if the corresponding promise
        // succeeded with a value or failed with an error
        results.forEach(function(pi, index) {
            if (pi.isFulfilled()) {
                console.log("Promise #" + (index + 1) + " succeeded with result " + pi.value());
            } else {
                console.log("Promise #" + (index + 1) + " failed with reason " + pi.reason());
            }
        });
    });
    

    或者,如果您不需要确切的错误,可以使用更简单的版本:

    $.settleVal(null, [ajax1Succes(), ajax2Success(), ajax3BoundtoFail()]).then(function(results) {
        // results contains the results from all the successful promises
        // any promises that has an error will show null as the result
    });
    

    请注意,它们使用的接口更像标准 Promise.all(),它们接受一组承诺并解析一组结果,因为这通常更容易在现实世界中使用。

    还有,这是实现:

    (function() {    
    
        function isPromise(p) {
            return p && (typeof p === "object" || typeof p === "function") && typeof p.then === "function";
        }
    
        function wrapInPromise(p) {
            if (!isPromise(p)) {
                p = $.Deferred().resolve(p);
            }
            return p;
        }
    
        function PromiseInspection(fulfilled, val) {
            return {
                isFulfilled: function() {
                    return fulfilled;
                }, isRejected: function() {
                    return !fulfilled;
                }, isPending: function() {
                    // PromiseInspection objects created here are never pending
                    return false;
                }, value: function() {
                    if (!fulfilled) {
                        throw new Error("Can't call .value() on a promise that is not fulfilled");
                    }
                    return val;
                }, reason: function() {
                    if (fulfilled) {
                        throw new Error("Can't call .reason() on a promise that is fulfilled");
                    }
                    return val;
                }
            };
        }
    
        // pass either multiple promises as separate arguments or an array of promises
        $.settle = function(p1) {
            var args;
            if (Array.isArray(p1)) {
                  args = p1;
            } else {
                args = Array.prototype.slice.call(arguments);
            }
    
            return $.when.apply($, args.map(function(p) {
                // make sure p is a promise (it could be just a value)
                p = wrapInPromise(p);
                // Now we know for sure that p is a promise
                // Make sure that the returned promise here is always resolved with a PromiseInspection object, never rejected
                return p.then(function(val) {
                    return new PromiseInspection(true, val);
                }, function(reason) {
                    // convert rejected promise into resolved promise by returning a resolved promised
                    // One could just return the promiseInspection object directly if jQuery was
                    // Promise spec compliant, but jQuery 1.x and 2.x are not so we have to take this extra step
                    return wrapInPromise(new PromiseInspection(false, reason));
                });
            })).then(function() {
                  // return an array of results which is just more convenient to work with
                  // than the separate arguments that $.when() would normally return
                return Array.prototype.slice.call(arguments);
            });
        }
    
        // simpler version that just converts any failed promises
        // to a resolved value of what is passed in, so the caller can just skip
        // any of those values in the returned values array
        // Typically, the caller would pass in null or 0 or an empty object
        $.settleVal = function(errorVal, p1) {
            var args;
            if (Array.isArray(p1)) {
                  args = p1;
            } else {
                args = Array.prototype.slice.call(arguments, 1);
            }
            return $.when.apply($, args.map(function(p) {
                p = wrapInPromise(p);
                return p.then(null, function(err) {
                    return wrapInPromise(errorVal);
                });
            }));
        }
    })();
    

    【讨论】:

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