链接Javascript承诺

lad*_*ini 3 javascript chaining promise

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

// 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.');
    });
Run Code Online (Sandbox Code Playgroud)

文档声明该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.');
    });
Run Code Online (Sandbox Code Playgroud)

如果是这样,那么这是不是意味着catch只有在从承诺返回p1.then的承诺被p1解决拒绝的情况下才会调用回调?我不是必须这样做的:

p1.then( /* etc. */ );
// and for rejected resolutions
p1.catch( /* etc. */ );
Run Code Online (Sandbox Code Playgroud)

抓住承诺的拒绝p1而不是链接catchthen

起初,我认为从中返回的承诺p1.thenp1jQuery如何处理其大部分API一样.但以下清楚地表明这两个承诺是不同的.

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 }
Run Code Online (Sandbox Code Playgroud)

另外,我在JSFiddle中玩了三种方法:

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

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

jfr*_*d00 6

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

p1.then(...)确实会返回一个链接到前一个的新承诺.因此,只有在第一个处理程序完成后p1.then(...).then(...)才会执行第二个.then()处理程序.并且,如果第一个.then()处理程序返回未实现的promise,那么在解析第二个promise并调用第二个.then()handler 之前,它将等待返回的promise返回.

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

此外,值得理解的.catch(fn)是,这只是一个捷径.then(null, fn).它没有区别.

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

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

如果是这样,那么这是不是意味着只有当从p1.then返回的promise而不是promise p1被拒绝时才会调用catch回调?我不是必须这样做的:

拒收立即向下传播链条的下一个拒绝处理,跳过所有解决处理. 因此,它将.catch()在您的示例中跳过链接到下一个链.

这是使用错误处理错误的事情之一.您可以放在.catch()链的末尾,它将从链中的任何位置捕获错误.

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

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

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

这三个都差不多. 2和3是相同的. 事实上,.catch(fn)无非就是捷径.then(null, fn).

选项1略有不同,因为如果onFulfilled处理程序抛出或返回被拒绝的promise,.catch()则会调用该处理程序.在另外两个选项中,情况并非如此.除了那一个差异,它将工作相同(如你所观察到的).

选项1有效,因为拒绝在链中传播.因此,如果p1拒绝或者onFulfilled处理程序返回被拒绝的promise或throws,则将.catch()调用该处理程序.