链接Javascript承诺 [英] Chaining Javascript promises

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

问题描述

我正在尝试从 MDN文档中了解Promise 。第一个示例演示然后 catch 方法:

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

文档说明然后方法返回一个新的承诺,所以不要将上述代码等同于

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

如果是,那么就不会这意味着只有当承诺从 p1.then 返回时才会调用 catch 回调,而不是承诺 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 链接到然后

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

起初,我认为从 p1.then 返回的承诺与 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);

  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?

推荐答案

首先,关于相关部分的一些背景知识承诺的工作:

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

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

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


如果是这样,那么这并不意味着只有当承诺从p1返回时,catch回调才会被称为
。然后,不是承诺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.

这是使用promises使错误处理变得简单的事情之一。您可以在链的末尾放置 .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 处理程序抛出或返回被拒绝的promise,然后将调用 .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处理程序返回被拒绝的promise或throws,则将调用 .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天全站免登陆