链接 Javascript 承诺 [英] Chaining Javascript promises

查看:24
本文介绍了链接 Javascript 承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从 MDN 文档中了解 Promises.第一个示例演示了 thencatch 方法:

I'm trying to understand Promises from the MDN documentation. The first example demonstrates the then and catch methods:

// 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,所以上面的代码不应该等同于

The documentation states that the then method returns a new promise, so shouln't the above code be equivalent to

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.');
    });

?

如果是这样,那么这是否意味着 catch 回调只会在 p1.then 返回的承诺而不是承诺 p1 返回时被调用,解决拒绝?难道我不必这样做:

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:

p1.then( /* etc. */ );
// and for rejected resolutions
p1.catch( /* etc. */ );

捕获对承诺的拒绝 p1 而不是将 catch 链接到 then?

to catch the rejection of the promise p1 instead of chaining the catch to the then?

起初,我认为 p1.then 返回的 promise 与 p1 相同,就像 jQuery 对其大部分 API 所做的一样.但下面清楚地表明,这两个承诺是不同的.

At first, I thought the promise returned from p1.then was the same as p1, like how jQuery does with much of its APIs. But the following clearly shows that the two promises are different.

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 中使用了三种方法:

Also, I played around in JSFiddle with the three approaches:

  1. p1.then(onFulfilled).catch(onRejected);
  2. p1.then(onFulfilled);p1.catch(onRejected);
  3. p1.then(onFulfilled, onRejected);

这三个都有效.后两者我能理解.我的问题的要点是,为什么第一种方法也有效?

All three work. I can understand the latter two. The gist of my question is, why does the first approach also work?

推荐答案

首先,关于 Promise 的相关部分如何工作的一些背景知识:

First, a little background on how the relevant parts of promises work:

p1.then(...) 确实返回一个链接到前一个的新承诺.所以,p1.then(...).then(...) 只会在第一个处理程序完成后执行第二个 .then() 处理程序.并且,如果第一个 .then() 处理程序返回一个未实现的承诺,那么它会在解析第二个承诺并调用第二个 .then()处理程序.

p1.then(...) does return a new promise that is chained to the previous one. So, p1.then(...).then(...) will execute the second .then() handler only after the first one has finished. And, if the first .then() handler returns an unfulfilled promise, then it will wait for that returned promise to resolve before resolving this second promise and calling that second .then() handler.

其次,当承诺链拒绝链中的任何地方时,它会立即向下跳过链(跳过任何已完成的处理程序),直到到达第一个拒绝处理程序(无论来自 .catch() 从第二个参数到 .then()).这是承诺拒绝的一个非常重要的部分,因为这意味着您不必在承诺链的每个级别都捕获拒绝.您可以将一个 .catch() 放在链的末尾,链中任何地方发生的任何拒绝都将直接转到该 .catch().

Secondly, when a promise chain rejects anywhere in the chain, it immediately skips down the chain (skipping any fulfilled handlers) until it gets to the first reject handler (whether that comes from a .catch() of from the second argument to .then()). This is a very important part of promise rejection because it means that you do not have to catch rejections at every level of the promise chain. You can put one .catch() at the end of the chain and any rejection that happens anywhere in the chain will go directly to that .catch().

另外,值得理解的是.catch(fn)只是.then(null, fn)的快捷方式.它的工作原理没有什么不同.

Also, it's worth understanding that .catch(fn) is just a shortcut for .then(null, fn). It works no differently.

另外,请记住(就像 .then())一个 .catch() 也将返回一个新的承诺.如果您的 .catch() 处理程序本身没有抛出或返回被拒绝的承诺,那么拒绝将被视为已处理"并且返回的承诺将得到解决,允许链从那里继续.这使您可以处理错误,然后有意识地决定是希望链继续正常执行逻辑还是保持拒绝.

Also, keep in mind that (just like .then()) a .catch() will also return a new promise. Any if your .catch() handler does not itself throw or return a rejected promise, then the rejection will be considered "handled" and the returned promise will resolve, allowing the chain to continue on from there. This allows you to handle an error and then consciously decide if you want the chain to continue with normal fulfill logic or stay rejected.

现在,对于您的具体问题...

Now, for your specific questions...

如果是这样,那是不是意味着会调用catch回调只有当承诺从 p1.then 返回时,而不是承诺 p1,决定拒绝?难道我不必这样做:

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().

No. Rejections propagate immediately down the chain to the next reject handler, skipping all resolve handlers. So, it will skip down the chain to the next .catch() in your example.

这是使用 Promise 使错误处理变得如此简单的原因之一.您可以将 .catch() 放在链的末尾,它会从链中的任何地方捕获错误.

This is one of the things that makes error handling so much simpler with promises. You can put .catch() at the end of the chain and it will catch errors from anywhere in the chain.

有时有理由在链的中间拦截错误(如果您想对错误进行分支和更改逻辑,然后继续使用其他代码),或者如果您想处理"错误并继续前进.但是,如果您的链是全有或全无,那么您只需在链的末尾放置一个 .catch() 即可捕获所有错误.

There are sometimes reasons to intercept errors in the middle of the chain (if you want to branch and change logic on an error and then keep going with some other code) or if you want to "handle" the error and keep going. But, if your chain is all or nothing, then you can just put one .catch() at the end of the chain to catch all errors.

它类似于同步代码中的 try/catch 块.在链的末尾放置一个 .catch() 就像在一堆同步代码的最高级别放置一个 try/catch 块.它将捕获代码中任何地方的异常.

It is meant to be analogous to try/catch blocks in synchronous code. Putting a .catch() at the end of the chain is like putting one try/catch block at the highest level around a bunch of synchronous code. It will catch exceptions anywhere in the code.

这三个都有效.后两者我能理解.我的要点问题是,为什么第一种方法也有效?

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) 的快捷方式.

All three are pretty much the same. 2 and 3 are identical. In fact, .catch(fn) is nothing more than a shortcut for .then(null, fn).

选项 1 略有不同 因为如果 onFulfilled 处理程序抛出或返回一个被拒绝的承诺,那么 .catch() 处理程序将得到叫.在其他两个选项中,情况并非如此.除了这一点不同外,它的工作原理相同(如您所见).

Option 1 is slightly different because if the onFulfilled handler throws or returns a rejected promise, then the .catch() handler will get called. In the other two options, that will not be the case. Other than that one difference, it will work the same (as you observed).

选项 1 有效,因为拒绝会沿链向下传播.因此,如果 p1 拒绝或者 onFulfilled 处理程序返回被拒绝的承诺或抛出,则 .catch() 处理程序将被调用.

Option 1 works because rejections propagate down the chain. So, if either p1 rejects or if the onFulfilled handler returns a rejected promise or throws, then the .catch() handler will be called.

这篇关于链接 Javascript 承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆