乐趣区

答疑解惑-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 带来帮助。

退出移动版