在 Promise 返回函数中找到第一个成功
Finding first success amongst Promise returning functions
给定一些函数,返回承诺:
function foo(arg) {
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
resolve('result from foo');
} else {
resolve(null);
}
});
);
// ... maybe more of these functions ...
function bar(arg) {
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
resolve('result from bar');
} else {
resolve(null);
}
});
);
我们如何以串行方式遍历函数,在第一个函数返回非空值后短路?
[
foo,
// ...
bar
].firstWithArg('some arg')
.then(function(result) {
// result: 'result from ___', or `null`
});
本质上,所需的行为是:
new Promise(function(resolve, reject){
foo('some-arg')
.then(function(result) {
if (result) {
resolve(result);
} else {
// ...
bar('some-arg')
.then(function(result) {
if (result) {
resolve(result);
} else {
resolve(null); // no functions left
}
})
}
});
});
Promise.race() 不能使用,因为函数不能全部触发。它们必须连续执行,在第一次成功后停止。
我认为没有为此预先构建的东西。您无需太多工作即可创建自己的。假设你有一个函数数组,在调用时 return 承诺。然后,您可以遍历该数组并在获得喜欢的结果时停止。当序列中的 promise 被拒绝时,不清楚你想做什么 - 这个实现会继续到下一个函数,但你可以为这种情况编写你想要的任何行为:
function iterateUntilGood(list, args) {
var cntr = 0;
return new Promise(function(resolve, reject) {
function next() {
if (list.length > cntr) {
list[cntr++].apply(null, args).then(function(result) {
// check the result here
if (some condition) {
resolve(result);
} else {
next();
}
}, next);
} else {
reject("No function succeeded");
}
}
next();
});
}
// usage
iterateUntilGood([fn1, fn2, fn3, fn4], [arg1, arg2]).then(function(result) {
// got result here
}, function(err) {
// handle error here
});
您说过您的第一个问题实际上只是为第二个问题做准备,这才是真正的问题。
所以我认为你的问题是:你如何执行一系列 return 连续承诺的函数,当第一个函数以非 null
值解析时短路?
我可能不会,我会使用 reject
而不是 resolve(null)
(但在评论中你已经澄清你想要 resolve(null)
,我明白你的意思;我在下面介绍):
function foo(arg) {
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
resolve('result from foo');
} else {
reject(); // <=== Note
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
resolve('result from bar');
} else {
reject(); // <=== Note
}
});
}
然后您使用 catch
处理拒绝,直到您得到解决方案:
foo("a")
.catch(() => bar(1))
.catch(() => foo("b"))
.catch(() => bar(2))
.catch(() => foo("c"))
.catch(() => bar(3))
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "rejecting");
reject(); // <=== Note
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "rejecting");
reject(); // <=== Note
}
});
}
foo("a")
.catch(() => bar(1))
.catch(() => foo("b"))
.catch(() => bar(2))
.catch(() => foo("c"))
.catch(() => bar(3))
.then(value => {
console.log("Done", value);
});
之所以可行,是因为解析会绕过 catch
处理程序,因此永远不会调用后续函数。
如果你有一组函数要调用,有一个成语:Array#reduce
:
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.catch(fn), Promise.reject())
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "rejecting");
reject(); // <=== Note
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "rejecting");
reject(); // <=== Note
}
});
}
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.catch(fn), Promise.reject())
.then(value => {
console.log("Done", value);
});
您可能知道,Array#reduce
对于 "reducing" 数组到一个值很有用,例如简单的求和:
[1, 2, 3].reduce((sum, value) => sum + value, 0); // 6
在上面,对于 "sum" 等效项,我们从一个被拒绝的承诺开始,并使用 catch
创建承诺链。调用 reduce
的结果是 catch
.
的最后承诺
但是,如果你想用resolve(null)
代替,你用类似的方式使用then
:
foo("a")
.then(result => result ? result : bar(1))
.then(result => result ? result : foo("b"))
.then(result => result ? result : bar(2))
.then(result => result ? result : foo("d"))
.then(result => result ? result : bar(3))
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "resolving null");
resolve(null);
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "resolving null");
resolve(null);
}
});
}
foo("a")
.then(result => result ? result : bar(1))
.then(result => result ? result : foo("b"))
.then(result => result ? result : bar(2))
.then(result => result ? result : foo("d"))
.then(result => result ? result : bar(3))
.then(value => {
console.log("Done", value);
});
或者用数组:
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.then(result => result ? result : fn()), Promise.resolve(null))
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "resolving null");
resolve(null);
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "resolving null");
resolve(null);
}
});
}
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.then(result => result ? result : fn()), Promise.resolve(null))
.then(value => {
console.log("Done", value);
});
这是有效的,因为如果我们得到一个真值(或者你可以使用 result => result !== null ? result : nextCall()
),我们 return 会沿着链条产生结果,这意味着 then
return 是具有该值的已解决承诺;但是如果我们得到一个虚假的值,我们会调用下一个函数和 return 它的承诺。
如您所见,这有点冗长,这就是为什么 promise 在解决和拒绝之间有这种区别的部分原因。
感谢@T.J.Crowder 和@jfriend00 的回答。
长话短说:
const arg = 'some common arg';
const functions = [
arg => new Promise((resolve, reject) => {
/* Does some work, then calls:
* resolve(something) if success
* resolve(null) if failure
* reject(error) if error
*/
})
]
functions.reduce(
(prev, fn) => prev.then(res => res ? res : fn(arg)),
Promise.resolve(null) // base case
) // returns promise which honours same contract as functions
// (resolves with something or null, or rejects with error)
Objective:遍历返回 Promises 的函数,直到我们成功 resolve
有一个值,然后我们短路。我们不想 Promise.race
,而是 运行 串行函数。
有关完整的工作示例,请参阅此代码段:
/* Define functions which return Promises honouring the following contract:
* switch (state) {
* case success:
* resolve(result);
* break;
* case failure:
* resolve(null);
* break;
* case error:
* reject(error);
* }
*/
const functions = [
arg => new Promise((resolve) => {
console.log('checking a against', arg);
if (arg === 'a') {
resolve('A');
} else {
resolve();
}
}),
arg => new Promise((resolve) => {
console.log('checking b against', arg);
if (arg === 'b') {
resolve('B');
} else {
resolve();
}
}),
// Intentionally omit handling 'c'
arg => new Promise((resolve, reject) => {
console.log('checking d against', arg);
if (arg === 'd') {
console.log('simulating error');
reject(new Error('D'));
} else {
resolve();
}
}),
arg => new Promise((resolve) => {
console.log('checking e against', arg);
if (arg === 'e') {
resolve('E');
} else {
resolve();
}
})
];
/* Successively call functions with given arg until we resolve a value,
* after which we short-circuit.
*/
function delegate(arg) {
console.log('\nDELEGATING for', arg);
functions.reduce(
// Note that this null comparison always happens N times,
// where N is the number of functions
// (unless one of the functions rejects)
(p, fn) => p.then(r => r ? r : fn(arg)),
Promise.resolve(null)
).then(value => {
console.log('Done:', value);
})
.catch(error => {
console.log('Error:', error);
});
}
// Run sample input through the delegate function
['a', 'b', 'c', 'd', 'e'].forEach(function(e, i) {
setTimeout(delegate.bind(null, e), i * 100); // delay, for printing
});
我使用建议的 reject(null)
策略实现了相同的示例,而不是 resolve(null)
,以表示不应停止函数迭代的非错误失败:
/* Define functions which return Promises honouring the following contract:
* switch (state) {
* case success:
* resolve(result);
* break;
* case failure:
* reject(null); // << NOTE
* break;
* case error:
* reject(error);
* }
*/
const functions = [
arg => new Promise((resolve, reject) => {
console.log('checking a against', arg);
if (arg === 'a') {
resolve('A');
} else {
reject();
}
}),
arg => new Promise((resolve, reject) => {
console.log('checking b against', arg);
if (arg === 'b') {
resolve('B');
} else {
reject();
}
}),
// Intentionally omit handling 'c'
arg => new Promise((resolve, reject) => {
console.log('checking d against', arg);
if (arg === 'd') {
console.log('simulating error');
reject(new Error('D'));
} else {
reject();
}
}),
arg => new Promise((resolve, reject) => {
console.log('checking e against', arg);
if (arg === 'e') {
resolve('E');
} else {
reject();
}
})
];
/* Successively call functions with given arg until we resolve a value,
* after which we short-circuit.
*/
function delegate(arg) {
console.log('\nDELEGATING for', arg);
functions.reduce(
// Check for error, or just rejection without value.
// Note that this check happens N-1 times,
// where N is the number of functions until one resolves
(p, fn) => p.catch(e => e ? Promise.reject(e) : fn(arg)),
Promise.reject()
).then(value => {
console.log('Done:', value);
})
.catch(error => {
console.log('Error:', error);
});
}
['a', 'b', 'c', 'd', 'e'].forEach(function(e, i) {
setTimeout(delegate.bind(null, e), i * 100); // delay, for printing
});
请注意,如果您阅读了@T.J.Crowder 的优秀示例,我们必须在 catch
函数中添加错误检查:
(p, fn) => p.catch(e => e ? Promise.reject(e) : fn(arg))
如果我们刚刚
(p, fn) => p.catch(() => fn(arg))
或
(p, fn) => p.catch(fn.bind(null, arg))
我们会默默地吸收错误(reject(error)
),然后继续,就好像我们只是遇到了一个非错误的失败。
考虑到这一点,我们最终通过使用 reject(null)
风格得到了更清晰、更高效(平均而言)的代码。
给定一些函数,返回承诺:
function foo(arg) {
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
resolve('result from foo');
} else {
resolve(null);
}
});
);
// ... maybe more of these functions ...
function bar(arg) {
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
resolve('result from bar');
} else {
resolve(null);
}
});
);
我们如何以串行方式遍历函数,在第一个函数返回非空值后短路?
[
foo,
// ...
bar
].firstWithArg('some arg')
.then(function(result) {
// result: 'result from ___', or `null`
});
本质上,所需的行为是:
new Promise(function(resolve, reject){
foo('some-arg')
.then(function(result) {
if (result) {
resolve(result);
} else {
// ...
bar('some-arg')
.then(function(result) {
if (result) {
resolve(result);
} else {
resolve(null); // no functions left
}
})
}
});
});
Promise.race() 不能使用,因为函数不能全部触发。它们必须连续执行,在第一次成功后停止。
我认为没有为此预先构建的东西。您无需太多工作即可创建自己的。假设你有一个函数数组,在调用时 return 承诺。然后,您可以遍历该数组并在获得喜欢的结果时停止。当序列中的 promise 被拒绝时,不清楚你想做什么 - 这个实现会继续到下一个函数,但你可以为这种情况编写你想要的任何行为:
function iterateUntilGood(list, args) {
var cntr = 0;
return new Promise(function(resolve, reject) {
function next() {
if (list.length > cntr) {
list[cntr++].apply(null, args).then(function(result) {
// check the result here
if (some condition) {
resolve(result);
} else {
next();
}
}, next);
} else {
reject("No function succeeded");
}
}
next();
});
}
// usage
iterateUntilGood([fn1, fn2, fn3, fn4], [arg1, arg2]).then(function(result) {
// got result here
}, function(err) {
// handle error here
});
您说过您的第一个问题实际上只是为第二个问题做准备,这才是真正的问题。
所以我认为你的问题是:你如何执行一系列 return 连续承诺的函数,当第一个函数以非 null
值解析时短路?
我可能不会,我会使用 reject
而不是 resolve(null)
(但在评论中你已经澄清你想要 resolve(null)
,我明白你的意思;我在下面介绍):
function foo(arg) {
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
resolve('result from foo');
} else {
reject(); // <=== Note
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
resolve('result from bar');
} else {
reject(); // <=== Note
}
});
}
然后您使用 catch
处理拒绝,直到您得到解决方案:
foo("a")
.catch(() => bar(1))
.catch(() => foo("b"))
.catch(() => bar(2))
.catch(() => foo("c"))
.catch(() => bar(3))
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "rejecting");
reject(); // <=== Note
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "rejecting");
reject(); // <=== Note
}
});
}
foo("a")
.catch(() => bar(1))
.catch(() => foo("b"))
.catch(() => bar(2))
.catch(() => foo("c"))
.catch(() => bar(3))
.then(value => {
console.log("Done", value);
});
之所以可行,是因为解析会绕过 catch
处理程序,因此永远不会调用后续函数。
如果你有一组函数要调用,有一个成语:Array#reduce
:
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.catch(fn), Promise.reject())
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "rejecting");
reject(); // <=== Note
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "rejecting");
reject(); // <=== Note
}
});
}
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.catch(fn), Promise.reject())
.then(value => {
console.log("Done", value);
});
您可能知道,Array#reduce
对于 "reducing" 数组到一个值很有用,例如简单的求和:
[1, 2, 3].reduce((sum, value) => sum + value, 0); // 6
在上面,对于 "sum" 等效项,我们从一个被拒绝的承诺开始,并使用 catch
创建承诺链。调用 reduce
的结果是 catch
.
但是,如果你想用resolve(null)
代替,你用类似的方式使用then
:
foo("a")
.then(result => result ? result : bar(1))
.then(result => result ? result : foo("b"))
.then(result => result ? result : bar(2))
.then(result => result ? result : foo("d"))
.then(result => result ? result : bar(3))
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "resolving null");
resolve(null);
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "resolving null");
resolve(null);
}
});
}
foo("a")
.then(result => result ? result : bar(1))
.then(result => result ? result : foo("b"))
.then(result => result ? result : bar(2))
.then(result => result ? result : foo("d"))
.then(result => result ? result : bar(3))
.then(value => {
console.log("Done", value);
});
或者用数组:
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.then(result => result ? result : fn()), Promise.resolve(null))
.then(value => {
console.log("Done", value);
});
function otherStuff(arg) {
return arg == 2;
}
function stuff(arg) {
return arg == "c";
}
function foo(arg) {
console.log("foo:", arg);
return new Promise(function(resolve, reject) {
if (stuff(arg)) {
console.log("foo:", arg, "resolving");
resolve('result from foo');
} else {
console.log("foo:", arg, "resolving null");
resolve(null);
}
});
}
// ... maybe more of these functions ...
function bar(arg) {
console.log("bar:", arg);
return new Promise(function(resolve, reject) {
if (otherStuff(arg)) {
console.log("bar:", arg, "resolving");
resolve('result from bar');
} else {
console.log("bar:", arg, "resolving null");
resolve(null);
}
});
}
let functions = [
() => foo("a"),
() => bar(1),
() => foo("b"),
() => bar(2),
() => foo("c"),
() => bar(3)
];
functions.reduce((p, fn) => p.then(result => result ? result : fn()), Promise.resolve(null))
.then(value => {
console.log("Done", value);
});
这是有效的,因为如果我们得到一个真值(或者你可以使用 result => result !== null ? result : nextCall()
),我们 return 会沿着链条产生结果,这意味着 then
return 是具有该值的已解决承诺;但是如果我们得到一个虚假的值,我们会调用下一个函数和 return 它的承诺。
如您所见,这有点冗长,这就是为什么 promise 在解决和拒绝之间有这种区别的部分原因。
感谢@T.J.Crowder 和@jfriend00 的回答。
长话短说:
const arg = 'some common arg';
const functions = [
arg => new Promise((resolve, reject) => {
/* Does some work, then calls:
* resolve(something) if success
* resolve(null) if failure
* reject(error) if error
*/
})
]
functions.reduce(
(prev, fn) => prev.then(res => res ? res : fn(arg)),
Promise.resolve(null) // base case
) // returns promise which honours same contract as functions
// (resolves with something or null, or rejects with error)
Objective:遍历返回 Promises 的函数,直到我们成功 resolve
有一个值,然后我们短路。我们不想 Promise.race
,而是 运行 串行函数。
有关完整的工作示例,请参阅此代码段:
/* Define functions which return Promises honouring the following contract:
* switch (state) {
* case success:
* resolve(result);
* break;
* case failure:
* resolve(null);
* break;
* case error:
* reject(error);
* }
*/
const functions = [
arg => new Promise((resolve) => {
console.log('checking a against', arg);
if (arg === 'a') {
resolve('A');
} else {
resolve();
}
}),
arg => new Promise((resolve) => {
console.log('checking b against', arg);
if (arg === 'b') {
resolve('B');
} else {
resolve();
}
}),
// Intentionally omit handling 'c'
arg => new Promise((resolve, reject) => {
console.log('checking d against', arg);
if (arg === 'd') {
console.log('simulating error');
reject(new Error('D'));
} else {
resolve();
}
}),
arg => new Promise((resolve) => {
console.log('checking e against', arg);
if (arg === 'e') {
resolve('E');
} else {
resolve();
}
})
];
/* Successively call functions with given arg until we resolve a value,
* after which we short-circuit.
*/
function delegate(arg) {
console.log('\nDELEGATING for', arg);
functions.reduce(
// Note that this null comparison always happens N times,
// where N is the number of functions
// (unless one of the functions rejects)
(p, fn) => p.then(r => r ? r : fn(arg)),
Promise.resolve(null)
).then(value => {
console.log('Done:', value);
})
.catch(error => {
console.log('Error:', error);
});
}
// Run sample input through the delegate function
['a', 'b', 'c', 'd', 'e'].forEach(function(e, i) {
setTimeout(delegate.bind(null, e), i * 100); // delay, for printing
});
我使用建议的 reject(null)
策略实现了相同的示例,而不是 resolve(null)
,以表示不应停止函数迭代的非错误失败:
/* Define functions which return Promises honouring the following contract:
* switch (state) {
* case success:
* resolve(result);
* break;
* case failure:
* reject(null); // << NOTE
* break;
* case error:
* reject(error);
* }
*/
const functions = [
arg => new Promise((resolve, reject) => {
console.log('checking a against', arg);
if (arg === 'a') {
resolve('A');
} else {
reject();
}
}),
arg => new Promise((resolve, reject) => {
console.log('checking b against', arg);
if (arg === 'b') {
resolve('B');
} else {
reject();
}
}),
// Intentionally omit handling 'c'
arg => new Promise((resolve, reject) => {
console.log('checking d against', arg);
if (arg === 'd') {
console.log('simulating error');
reject(new Error('D'));
} else {
reject();
}
}),
arg => new Promise((resolve, reject) => {
console.log('checking e against', arg);
if (arg === 'e') {
resolve('E');
} else {
reject();
}
})
];
/* Successively call functions with given arg until we resolve a value,
* after which we short-circuit.
*/
function delegate(arg) {
console.log('\nDELEGATING for', arg);
functions.reduce(
// Check for error, or just rejection without value.
// Note that this check happens N-1 times,
// where N is the number of functions until one resolves
(p, fn) => p.catch(e => e ? Promise.reject(e) : fn(arg)),
Promise.reject()
).then(value => {
console.log('Done:', value);
})
.catch(error => {
console.log('Error:', error);
});
}
['a', 'b', 'c', 'd', 'e'].forEach(function(e, i) {
setTimeout(delegate.bind(null, e), i * 100); // delay, for printing
});
请注意,如果您阅读了@T.J.Crowder 的优秀示例,我们必须在 catch
函数中添加错误检查:
(p, fn) => p.catch(e => e ? Promise.reject(e) : fn(arg))
如果我们刚刚
(p, fn) => p.catch(() => fn(arg))
或
(p, fn) => p.catch(fn.bind(null, arg))
我们会默默地吸收错误(reject(error)
),然后继续,就好像我们只是遇到了一个非错误的失败。
考虑到这一点,我们最终通过使用 reject(null)
风格得到了更清晰、更高效(平均而言)的代码。