如果将解决任何一个承诺,则返回成功函数

时间:2015-01-20 15:40:34

标签: jquery

我正在学习使用Promises。以下我知道的事情:

$.when(promise1,promise2,promise3).then(doneCallback, failCallback);

使用.when()方法,当所有承诺都得到解决后,doneCallback将会返回,当任何承诺被拒绝时,failCallback将会返回。

但是我想知道如果任何一个承诺得到解决而其他承诺可能被拒绝,那么是否有任何办法可以做,doneCallback将会返回。

我不知道这是否适用于现实世界的用例。但我只是想知道是否有办法 - 怎么做?

4 个答案:

答案 0 :(得分:1)

您可以跟踪每个承诺状态,如果至少有一个承诺被解析,则将布尔变量设置为true。如果布尔值为true,则解析主延迟对象,否则拒绝它,例如

function checkPromises() {
    var onePromisesResolved = false;
    var checkedPromises = 0;
    var dfd = $.Deferred();


    var markPromise = function() {
        checkedPromises++;
        if (checkedPromises === 3) {
            if (onePromisesResolved) {
                dfd.resolve();
            }
            else {
                dfd.reject();
            }
        }
    }  
    var checkResolved = function() {
       onePromisesResolved = onePromisesResolved || true; 
       markPromise();
    }
    var checkFailed = function() {
       onePromisesResolved = onePromisesResolved || false; 
       markPromise();
    }

    $.when(promise1).then(checkResolved, checkFailed);
    $.when(promise2).then(checkResolved, checkFailed);
    $.when(promise3).then(checkResolved, checkFailed);

    return dfd.promise();
};  

$.when(checkPromises).then(doneCallback, failCallback)

如果至少解决了一个promise,那么布尔变量为true(它是or连接表达式的结果)

答案 1 :(得分:1)

如果你需要检查一种承诺类型,我相信你必须采取不同的方法。 Jquery $ .when()函数接受一个promises列表,一个接一个地执行它们,当完成所有操作后,调用成功处理程序。但是在失败的第一个承诺上,控件立即转到then()部分。这是它的标准行为。 如果您预期一个承诺可以被拒绝而其他承诺会对其进行补偿,那么您需要为该案例创建一个单独的承诺,并将其列在您的$ .when(..)调用中。 请参阅以下代码以说明上述方法。



  
    
    var firstUrl = 'http://www.html5rocks.com/en/tutorials/file/xhr2/';
    var secondUrl = 'http://www.html5rocks.com/en/tutorials/audio/scheduling/';
    
    function documentReady() {
      var deferredReady = $.Deferred();
      $(document).ready(function() {
          deferredReady.resolve();
        });
      return deferredReady.promise();
    }
    
    function firstCompleted(url1, url2) {
      var deferredFirst = $.Deferred();
      
      $.get(url1, function(data, status) {
        if ('success' == status) {
          deferredFirst.resolve(url1);
        }
      });
      
      $.get(url2, function(data, status) {
        if ('success' == status) {
          deferredFirst.resolve(url2);
        }
      });
      
      return deferredFirst.promise();
    }
    
    $.when (documentReady(), firstCompleted(firstUrl, secondUrl) ).then(
      function (readyData, firstData) {
        $('#winner').html("The winner is " + firstData);
    });

<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<div id="winner"></div>
&#13;
&#13;
&#13; 你的问题的直接答案是否,你不能让其中一个承诺失败,仍然会调用successHandler。

答案 2 :(得分:0)

您需要使用像Bluebird这样的专用Promises库,它支持some()any()

https://github.com/petkaantonov/bluebird/blob/master/API.md#someint-count---promise

这可能有效

function anyPromise() {
    var def = $.Deferred(),
        rejectCount = 0;

    $.each(arguments, function (i, promise) {
        promise.then(function (value) {
            if (def.state() === 'pending')
                def.resolve(value);
        }, function (value) {
            rejectCount++;
            if (rejectCount === arguments.length)
                def.reject(value);
        });
    });

    return def.promise();
}

anyPromise(promise1, promise2, promise3).then(doneCallback, failCallback);

答案 3 :(得分:0)

修改,更新

尝试使用deferred.always()

(function ($) {
    $.whenAt = whenAt;   
    function whenAt() {
        var args = Array.prototype.slice.call(arguments[0]) // promises
            // resolve `whenAt` at `resolveAt` : `Number` ,
            // of resolved `args` promises
            , resolveAt = Array.prototype.slice.call(arguments[1]) 
            , deferred = new $.Deferred()
            , promises = p = {
                "resolved": [],
                "rejected": []
            }
            , doneCallback = function (res, state) {
                promises[state].push(res);
                // console.log(res, promises, $.now());
                // strict comparison `===` may not be accurate
                // due to asynchronous returned promise values ,
                // return true if resolved length `>=` resolveAt
                return (p.resolved.length >= resolveAt) 
                        ? deferred.resolve(promises) : res
            }, failCallback = function (res, state) {
                promises[state].push(res);
                // console.log(res, promises, $.now());
                return (p.resolved.length + p.rejected.length) === args.length 
                ? deferred.resolve(promises) : res
            };
        $.map(args, function (promise, index) {
            return promise.always(function (data) {
                var state = this.state();
                return state === "resolved" ? doneCallback.call(this, {
                    index: index, // log `index` of `resolved`
                    data: data 
                }, state) : failCallback.call(this, {
                    index: index, // log `index` of `rejected`
                    data: data
                }, state)
            })
        });
        return deferred.promise()
    };
}(jQuery));

// e.g.,
var arr = [1, 2, 3, 4, 5]

, dfd = function (i) {
            return new $.Deferred(function (d) {
                setTimeout(function () {
                    // throw `error` if `i` === 2
                    if (i === 2) d.reject(new Error("error").message)
                    else d.resolve(i)
                }, 1 + Math.floor(Math.random() * 5000));
            }).promise()
         }

, results = $("#results");

$.whenAt([
    dfd(1)
    , dfd(2)
    , dfd(3)
    , dfd(4)
    , dfd(5)
    , $.Deferred(function (d) {
          setTimeout(function () {
              // throw `error`
              d.reject(new Error("error").message)
          }, 1 + Math.floor(Math.random() * 5000));
          return d.promise()
      })
], 1) // `1` : `resolveAt`
.then(function (data) {
    results.append("\npromises:\r\n" + JSON.stringify(data, null, 4));
    console.log(data.resolved[0]); // first resolved promise
});

var arr = [1, 2, 3, 4, 5]

,
dfd = function (i) {
    return new $.Deferred(function (d) {
        setTimeout(function () {
            if (i === 2) d.reject(new Error("error").message)
            else d.resolve(i)
        }, 1 + Math.floor(Math.random() * 5000));
    }).promise()
}, results = $("#results");

(function ($) {
$.whenAt = whenAt;

function whenAt() {
    var args = Array.prototype.slice.call(arguments[0]),
        resolveAt = Array.prototype.slice.call(arguments[1]);
        var deferred = new $.Deferred(),
        promises = p = {
            "resolved": [],
            "rejected": []
        }, doneCallback = function (res, state) {
            promises[state].push(res);
            console.log(res, promises, $.now());
            return (p.resolved.length >= resolveAt) 
                    ? deferred.resolve(promises) : res
        }, failCallback = function (res, state) {
            promises[state].push(res);
            console.log(res, promises, $.now());
            return (p.resolved.length + p.rejected.length) === args.length 
            ? deferred.resolve(promises) : res
        };
    $.map(args, function (promise, index) {
        return promise.always(function (data) {
            var state = this.state();
            return state === "resolved" ? doneCallback.call(this, {
                index: index,
                data: data
            }, state) : failCallback.call(this, {
                index: index,
                data: data
            }, state)
        })
    });
    return deferred.promise()
};
}(jQuery));

$.whenAt([
dfd(1), dfd(2), dfd(3), dfd(4), dfd(5), $.Deferred(function (d) {
setTimeout(function () {
    d.reject(new Error("error").message)
}, 1 + Math.floor(Math.random() * 5000));
return d.promise()
})], 1)
.then(function (data) {
results.append("\nresolvedAt:\r\n" + JSON.stringify(data.resolved, null, 4));
console.log("resolvedAt:", data.resolved[0])
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<pre id="results"></pre>