我理解使用Q
库很容易等待许多承诺完成,然后使用与这些承诺结果相对应的值列表:
Q.all([
promise1,
promise2,
.
.
.
promiseN,
]).then(results) {
// results is a list of all the values from 1 to n
});
但是,如果我只对单一,快速完成的结果感兴趣,会发生什么?给出一个用例:假设我有兴趣检查一个大的文件列表,一旦找到包含“"津巴布韦"”这个词的任何文件,我就会对内容感兴趣。
我可以这样做:
Q.all(fileNames.map(function(fileName) {
return readFilePromise(fileName).then(function(fileContents) {
return fileContents.contains('zimbabwe') ? fileContents : null;
}));
})).then(function(results) {
var zimbabweFile = results.filter(function(r) { return r !== null; })[0];
});
但即使我已经找到"津巴布韦"我也需要完成处理每个文件。如果我有一个包含"津巴布韦"的2kb文件,以及一个不包含"津巴布韦"的30tb文件(并假设我是异步读取文件) - 这是愚蠢的!
我希望能够做到的是在任何承诺得到满足时获得价值:
Q.any(fileNames.map(function(fileName) {
return readFilePromise(fileName).then(function(fileContents) {
if (fileContents.contains('zimbabwe')) return fileContents;
/*
Indicate failure
-Return "null" or "undefined"?
-Throw error?
*/
}));
})).then(function(result) {
// Only one result!
var zimbabweFile = result;
}).fail(function() { /* no "zimbabwe" found */ });
如果"津巴布韦"采用这种方法,我不会等待我的30tb文件。早在我的2kb文件中就被发现了。
但是没有Q.any
这样的东西!
我的问题:我如何得到这种行为?
重要提示:即使其中一个内部承诺发生错误,也应该没有错误地返回。
注意:我知道我可以通过在找到第一个有效值时抛出错误来Q.all
,但我更愿意避免这种情况。
注意:我知道Q.any
- 行为可能不正确,或在许多情况下不合适。请相信我有一个有效的用例!
答案 0 :(得分:1)
你混合了两个不同的问题:比赛和取消。
使用Promise.race
或您最喜欢的诺言库中的等效物品,可以轻松实现赛车。如果您愿意,可以自己写两行:
function race(promises) {
return new Promise((resolve, reject) =>
promises.forEach(promise => promise.then(resolve, reject)));
}
如果任何承诺拒绝,那将拒绝。如果您想要跳过拒绝,并且只拒绝所有承诺拒绝,那么
function race(promises) {
let rejected = 0;
return new Promise((resolve, reject) =>
promises.forEach(promise => promise.then(resolve,
() => { if (++rejected === promises.length) reject(); }
);
}
或者,您可以将promise inversion trick与Promise.all
一起使用,我不会在此处讨论。
你真正的问题是不同的 - 你显然想要在其他人解决时“取消”其他承诺。为此,您需要额外的专业机器。表示每个处理段的对象需要某种方式来要求它终止。这是一些伪代码:
class Processor {
promise() { ... }
terminate() { ... }
}
现在您可以将您的种族版本编写为
function race(processors) {
let rejected = 0;
return new Promise((resolve, reject) =>
processors.forEach(processor => processor.promise().then(
() => {
resolve();
processors.forEach(processor => processor.terminate());
},
() => { if (++rejected === processors.length) reject(); }
);
);
}
有许多处理承诺取消的建议,这些建议可能会在几年内实施时更容易。