首页 文章

链接Javascript承诺

提问于
浏览
3

我试图理解MDN documentation中的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>)
'); }) .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>)
'); }); p2.catch( // Log the rejection reason function(reason) { console.log('Handle rejected promise ('+reason+') here.'); });

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

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

grab 承诺的拒绝 p1 而不是将 catch 链接到 then

起初,我认为从 p1.then 返回的承诺与 p1 相同,就像jQuery如何处理其大部分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 }

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

  • p1.then(onFulfilled).catch(onRejected);

  • p1.then(onFulfilled); p1.catch(onRejected);

  • p1.then(onFulfilled, onRejected);

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

3 回答

  • 3

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

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

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

    此外,值得理解 .catch(fn) 只是 .then(null, fn) 的快捷方式 . 它没有区别 .

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

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

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

    No. Rejections propagate immediately down the chain to the next reject handler, skipping all resolve handlers. 因此,在您的示例中,它将跳过链到下一个 .catch() .

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

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

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

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

    这三个都差不多 . 2 and 3 are identical. 事实上, .catch(fn) 只不过是 .then(null, fn) 的快捷方式 .

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

    Option 1 works because rejections propagate down the chain. 因此,如果p1拒绝或者onFulfilled处理程序返回被拒绝的promise或throws,则将调用 .catch() 处理程序 .

  • 0

    代码不应该是等同的

    他们是 .

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

    对,就是这样 .

    但是当 p1 拒绝时, p2 也会这样做,因为你没有将 onRejected 处理程序传递给已截获它的 .then() 调用 . 拒绝只是沿着链传播 .

    我在JSFiddle中玩了三种方法 . 这三个都有效 .

    他们这样做,但他们不这样做 .

    p1.then(onFulfilled,onRejected);

    这是你通常想要的去做 .

    p1.then(onFulfilled); p1.catch(onRejected);

    这最终会产生两个不同的承诺,一个将用 onFulfilled 结果解决或被拒绝,另一个将用 onRejected 结果来实现或解决 .

    p1.then(onFulfilled).catch(onRejected);

    那是一个与第一个不同的野兽,见When is .then(success, fail) considered an antipattern for promises? .

  • 6

    这个:

    var p2 = p1.then()
    p2.catch()
    

    与此相同:

    p1.then().catch()
    

    你也可以这样做:

    p1
     .then(response => response.body)
     .then(body => JSON.parse(body))
     .then(data => console.log(data))
     .catch(e => console.log('something somewhere failed'))
    

相关问题