我试图从 MDN documentation 中理解 Promises .第一个示例演示了 then
和 catch
方法:
// We define what to do when the promise is resolved/fulfilled with the then() call,
// and the catch() method defines what to do if the promise is rejected.
p1.then(
// Log the fulfillment value
function(val) {
log.insertAdjacentHTML('beforeend', val +
') Promise fulfilled (<small>Async code terminated</small>)<br/>');
})
.catch(
// Log the rejection reason
function(reason) {
console.log('Handle rejected promise ('+reason+') here.');
});
文档指出 then
方法返回一个新的 promise ,所以上面的代码不应该等同于
var p2 = p1.then(
// Log the fulfillment value
function(val) {
log.insertAdjacentHTML('beforeend', val +
') Promise fulfilled (<small>Async code terminated</small>)<br/>');
});
p2.catch(
// Log the rejection reason
function(reason) {
console.log('Handle rejected promise ('+reason+') here.');
});
?
如果是这样,那是否意味着只有当 promise 从 p1.then
返回时才会调用 catch
回调,而不是 promise p1
,决定拒绝?难道我不必这样做:
p1.then( /* etc. */ );
// and for rejected resolutions
p1.catch( /* etc. */ );
捕捉 promise p1
的拒绝,而不是将 catch
链接到 then
?
起初,我认为从 p1.then
返回的 promise 与 p1
相同,就像 jQuery 对其大部分 API 的处理方式一样。但是下面清楚地表明这两个 promise 是不同的。
var p1 = new Promise(function(resolve, reject) {
resolve("Success!");
});
console.log(p1);
// Promise { <state>: "fulfilled", <value>: "Success!" }
var p2 = p1.then(function(value) {
console.log(value);
});
// Success!
console.log(p2);
// Promise { <state>: "fulfilled", <value>: undefined }
另外,我在 JSFiddle 中尝试了三种方法:
p1.then(onFulfilled).catch(onRejected);
p1.then(onFulfilled); p1.catch(onRejected);
p1.then(onFulfilled, onRejected);
这三个都有效。后两者我能理解。我的问题的要点是,为什么第一种方法也有效?
最佳答案
首先,介绍一下 promises 相关部分的工作原理:
p1.then(...)
确实返回一个链接到前一个的新 promise 。因此,p1.then(...).then(...)
将仅在第一个处理程序完成后执行第二个 .then()
处理程序。并且,如果第一个 .then()
处理程序返回一个未实现的 promise ,那么它将等待返回的 promise 得到解决,然后再解决第二个 promise 并调用第二个 .then()
处理程序。
其次,当 promise 链在链中的任何地方拒绝时,它会立即跳过链(跳过任何已完成的处理程序)直到它到达第一个拒绝处理程序(无论它来自 .catch()
从第二个参数到 .then()
)。这是 promise 拒绝的一个非常重要的部分,因为这意味着您不必在 promise 链的每个级别都捕获拒绝。您可以将一个 .catch()
放在链的末尾,链中任何位置发生的任何拒绝都将直接转到该 .catch()
。
此外,值得理解的是 .catch(fn)
只是 .then(null, fn)
的快捷方式。它的工作原理没有什么不同。
此外,请记住(就像.then()
).catch()
也会返回一个新的promise。 Any 如果您的 .catch()
处理程序本身没有抛出或返回被拒绝的 promise ,那么拒绝将被视为“已处理”并且返回的 promise 将得到解决,从而允许链从那里继续。这允许您处理错误,然后有意识地决定您是希望链继续执行正常的履行逻辑还是保持被拒绝状态。
现在,针对您的具体问题...
If so, then wouldn't that mean that the catch callback would be called only if the promise returned from p1.then, not the promise p1, resolved to rejected? And wouldn't I have to do this:
没有。 拒绝立即沿着链向下传播到下一个拒绝处理程序,跳过所有解析处理程序。因此,它会沿着链向下传播到您示例中的下一个 .catch()
。
这是使用 promises 使错误处理变得如此简单的原因之一。您可以将 .catch()
放在链的末尾,它会捕获链中任何位置的错误。
有时有理由在链的中间拦截错误(如果你想分支并更改错误的逻辑然后继续处理其他代码)或者如果你想“处理”错误并继续前进.但是,如果您的链是全有或全无,那么您只需在链的末尾放置一个 .catch()
即可捕获所有错误。
它类似于同步代码中的 try/catch block 。将 .catch()
放在链的末尾就像将一个 try/catch block 放在一堆同步代码的最高层。它将捕获代码中任何位置的异常。
All three work. I can understand the latter two. The gist of my question is, why does the first approach also work?
这三个都差不多。 2 和3 是相同的。 事实上,.catch(fn)
只不过是.then(null, fn)
的快捷方式。
选项 1 略有不同,因为如果 onFulfilled
处理程序抛出或返回一个被拒绝的 promise ,那么 .catch()
处理程序将得到叫。在其他两个选项中,情况并非如此。除了这一点不同,它的工作原理是一样的(如您观察到的那样)。
选项 1 有效,因为拒绝沿着链传播。因此,如果 p1 拒绝或者如果 onFulfilled 处理程序返回被拒绝的 promise 或抛出,则 .catch()
将调用处理程序。
关于javascript - 链接 Javascript promise ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38451166/