有一个区别——这应该不重要——其他答案都没有涉及到,所以:
如果传递给then抛出的实现处理程序,则调用then返回的承诺连同抛出的内容一起被拒绝。
如果它返回一个被拒绝的承诺,那么调用返回的承诺将被解析为该承诺(并且最终将被拒绝,因为它被解析的承诺被拒绝了),这可能会引入一个额外的异步“tick”(在微任务队列中多一个循环,用浏览器的术语来说)。
然而,任何依赖于这种差异的代码都从根本上被破坏了。:-)它不应该对承诺和解的时间那么敏感。
这里有一个例子:
function usingThrow(val) {
return Promise.resolve(val)
.then(v => {
if (v !== 42) {
throw new Error(`${v} is not 42!`);
}
return v;
});
}
function usingReject(val) {
return Promise.resolve(val)
.then(v => {
if (v !== 42) {
return Promise.reject(new Error(`${v} is not 42!`));
}
return v;
});
}
// The rejection handler on this chain may be called **after** the
// rejection handler on the following chain
usingReject(1)
.then(v => console.log(v))
.catch(e => console.error("Error from usingReject:", e.message));
// The rejection handler on this chain may be called **before** the
// rejection handler on the preceding chain
usingThrow(2)
.then(v => console.log(v))
.catch(e => console.error("Error from usingThrow:", e.message));
如果你运行它,在写这篇文章时,你会得到:
Error from usingThrow: 2 is not 42!
Error from usingReject: 1 is not 42!
注意顺序。
将其与相同的链进行比较,但都使用usingThrow:
函数usingThrow(val) {
返回Promise.resolve (val)
.then(v => {
If (v !== 42) {
抛出新的错误(' ${v}不是42! ');
}
返回v;
});
}
usingThrow (1)
.then(v => console.log(v))
.catch(e =>控制台。error(" error from usingThrow:", e.message));
usingThrow (2)
.then(v => console.log(v))
.catch(e =>控制台。error(" error from usingThrow:", e.message));
这表明拒绝处理程序以另一种顺序运行:
Error from usingThrow: 1 is not 42!
Error from usingThrow: 2 is not 42!
我在上面说“可能”,是因为在其他领域已经有一些工作,在其他类似的情况下,如果所有涉及的承诺都是本机承诺(而不仅仅是thenable),那么就去掉了这个不必要的额外标记。(具体来说:在一个异步函数中,return await x最初引入了一个额外的async tick,而return x在其他方面是相同的;ES2020改变了它,如果x是原生承诺,在没有其他差异的地方,额外的勾将被删除。)
同样,任何对承诺的结算时间如此敏感的代码都已经被破坏了。所以这真的不重要。
实际上,正如其他回答所提到的:
正如Kevin B指出的,如果你在回调到你在实现处理程序中使用的其他函数中,throw将不起作用——这是一个大问题
正如lukyer指出的那样,throw会突然终止函数,这可能很有用(但在示例中使用的是return,它做的是同样的事情)
正如venator指出的那样,你不能在条件表达式(?:),至少现在还没有
除此之外,这主要是风格/偏好的问题,所以对于大多数情况,你要与你的团队达成一致(或者你不在乎任何一种方式),并保持一致。