我正在学习使用Promises。以下我知道的事情:
$.when(promise1,promise2,promise3).then(doneCallback, failCallback);
使用.when()
方法,当所有承诺都得到解决后,doneCallback
将会返回,当任何承诺被拒绝时,failCallback
将会返回。
但是我想知道如果任何一个承诺得到解决而其他承诺可能被拒绝,那么是否有任何办法可以做,doneCallback
将会返回。
我不知道这是否适用于现实世界的用例。但我只是想知道是否有办法 - 怎么做?
答案 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;
答案 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)
修改,更新
(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>