Promise

95 阅读4分钟

Promise

1、定义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

2、信任问题

以下是只用回调编码存在的信任问题:

• 调用回调过早;

• 调用回调过晚(或不被调用);

• 调用回调次数过少或过多;

• 未能传递所需的环境和参数;

• 吞掉可能出现的错误和异常。

Promise 的特性就是专门用来为这些问题提供一个有效的可复用的答案。

  • 调用回调过早:Promise不需要担心这个问题,因为即使是立即执行,也不能被同步获取到,他会将所有的流都转成异步流。
  • 调用回调过晚:Promise只要被决议过,只要调用then都会拿到。根据js执行机制,回调都会在下一个异步时机点上依次被立即调用,不存在抢占。
  • 调用回调次数过多或者过少:Promise定义的方式使其只能被决议一次,即使在内部调用resolve()或者reject()多次,只是接受第一次。另外注册thend多次,那么他被调用的次数和他被注册的次数一致。
  • 未能传递参数:Promise 至多只能有一个决议值(完成或拒绝),如果需要多个只能自己放到数组中或者对象,如果没有传值,默认是undefined。
  • 吞掉可能出现的错误:promise会在reject函数中捕获错误。但是其比复杂,会在捕获错误部分讲解。

3、状态

Promise只有3中状态,pendding(进行中),fulfilled(已成功),rejected(已拒绝)

Promise状态一旦改变,就不会再变化了。

Promise状态只能是从pedding=>fulfilled,或者是pedding=>rejected.

4、API

  • 通过构造函数创建promise

image.png

  • Promise.resolve() 完成,可以是成功状态也可以是拒绝状态

Promise.resolve(any)

如果any是一个promise,则直接将这个值返回,如果是thenable则会展开这个therable,然后将其对应值返回。如果是一个常量就将这个常量返回。

在resolve内,如果有错误或者添加promise的reject() ,其状态就会变为rejected状态。

  • Promise.reject()拒绝,只能是拒绝。

Promise.reject())

  • then/catch

每个promise实例都会有then和catch方法。

image.png 如果之用失败没有成功,则如下

image.png

  • Promise.all([...])/Promise.race([...])

Promise.all()传入一个数组,数组内的任务(可同步可异步),全部成功则成功,否则有一个拒绝,Promise.all就立刻拒绝。如果传入一个空数组,则会立刻成功。

Promise.race([...])也是传入一个数组,数组内的任务(可同步可异步),只要有一个拒绝,则promise.race()立刻拒绝。如果传入空数组,Promise不会立即决议,而是一直pedding,永不成功。

5、Promise错误判断

由于Promise一旦决议状态就不在改变,导致Promise如果状态以改变后,又出现错误,这只能再下一次回调中捕获到错误,如果下次回调中仍然出现错误,则只能再等下一次的异步回调中捕获到错误,如此,则可能一直不能捕获到错误。

解决方法:1、在最外层添加catch,可以捕获所有catch之前的错误,但是catch内的错误仍旧需要在下一次回调中捕获。

2、在最外层添加done函数,从本质上讲,done函数标识这Promise链的结束。done()不会再创建和返回Promise,所以传道给done()的回调不会报告一个并不是Promise的问题。如果done函数内发生错误,则会被当做一个全局错误抛出。

3、使用defer

使用defer必须手动定义reject函数,否则仍旧是会抛出全局错误。

image.png 6、局限性

  • 顺序错误处理
  • 单一值
  • 单决议
  • 惯性
  • 无法取消的Promise
  • Promise性能