答疑解惑 -- Promise

Promise

本章主要是解释几个大部分人关于promise疑惑的地方,或者可能跟你想象不太一样的地方,所以需要对promise有一定的基础才行,最好在项目里用过。
在开始之前,先跟大家确认一个概念:决议。决议就是promise的判定。比如执行reslove()或者reject(),这个promsie就被判定成一个状态了,或者说被决议了

promise 语法格式

在语法格式方面,好像我们都知道,也经常用。比如我们最常见的写法

let promise = new Promise((resolve, reject) => {
   // to do some thing
   console.log(a);
   resolve();
});
promise.then(() => {
   console.log('run success');
})
.catch(() => {
   console.log('run fail');
})

这个格式写法完全没有错。而且很多书上都推荐这么写。尤其是链式写法(then-then-catch)。
但promise的格式其实不是这样的。它应该是下面这样的。

let promise = new Promise((resolve, reject) => {
   // to do some thing
   console.log(a);
   resolve();
});
promise.then(() => {
   console.log('run success');
}, () => {
   console.log('run fail')
})
.catch(() => {
   console.log('run fail');
})

这个里面的then里应该有两个参数(两个回调,一个用来接收成功决议,一个接收失败决议)。只是我们经常把第二个参数省略了,或者说为了代码写起来方便,看起来舒服,我们故意的。
读到这里你可以疑惑,这个有什么的呢,不就是少写一个回调嘛。这个在写代码中确实没有作用,但是在理解promise里的某些东西却是非常重要(下面会举到这个例子)。这里可以给你抛出一个问题:为什么catch 能够抓到好几个then之前报的错呢?

只一次决议

之前有同事问这个问题:下面的代码里为啥会执行出success, 为啥不是进入catch里呢(方法b会抛出异常啊)?您是否知道原因呢?

console.log('here')

new Promise(resolve => {
  resolve()
  console.log('000')
  b()
}).then( value => {
   console.log('success');
})
.catch( error => {
  console.log('Erro123r', error.message)
})

function b() {
  console.log(999)
  throw new Error('123')
}

这个就是promise一个最重要的特性。一次决议后,就不可更改。所以本题的核心就是在先执行reslove(),再执行b方法,执行reslove决议已经定了,b的报错已经无法改不决议的结果了。所以它只能走then,而不走catch。如果我们想要进入catch,只需要b方法执行放到resolve前面,错误先让promise进行决议。
promise 只决议一次才是我们放心大胆的用的保证,否者我们都得考虑它此时决议结果是什么。我可以放心大胆的像下面这么写:可以写好多个then,而不用担心决议改不了,then 不会执行。

function bar() {
 // to do something
}
function foo() {
 // to do something
}
let p = new Promise((resolve, reject) => {
     //  to do something
     resolve();
})
p.then(bar);
p.then(foo);
.
.
.

为什么catch 能够抓到好几个then之前报的错呢?

我们先来看看链式结构,省略then里的回调方法。

let p = Promise.resolve();
p.then().then().then().then().catch()

链接结构就是这样吧。看到这个结构就解答了常见的很多人都会理解错误的一个误区(p的决议是reject后,会直接执行catch)。
从这个链式结构上看,我们代码的执行不可能不执行then,或者说跳过前面的then,直接执行catch。我们只能链式调用,一个then,一个then的调用。直到调用到最后的catch。此时我们得到一个重要的结论:
then方法不管是决议成功和失败它都会执行
此时有人会疑惑,如果then都执行的话,then里回调不就被执行了吗?
这个就是我们在第一部分介绍promise的格式了。then里面有两个参数(成功回调,失败回调)。一旦决议失败,then里的失败回调就会执行。但是一般情况下,我们不写失败回调。promise会自动补充一个失败回调,同时会把失败的状态传递给下一个then。一个一个的往下传递,只要下面的then都不写失败回调,就会一直传递下去,直到遇到catch。
这个就是为什么catch能够抓到好几个then之前报的错误。

这些都是我花很多时间学习,同时花了很久时间码字。希望能够给大家对理解promise带来帮助。
《答疑解惑 -- Promise》

    原文作者:philips
    原文地址: https://segmentfault.com/a/1190000020262846
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞