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
- Promise.resolve() 完成,可以是成功状态也可以是拒绝状态
Promise.resolve(any)
如果any是一个promise,则直接将这个值返回,如果是thenable则会展开这个therable,然后将其对应值返回。如果是一个常量就将这个常量返回。
在resolve内,如果有错误或者添加promise的reject() ,其状态就会变为rejected状态。
- Promise.reject()拒绝,只能是拒绝。
Promise.reject())
- then/catch
每个promise实例都会有then和catch方法。
如果之用失败没有成功,则如下
- 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函数,否则仍旧是会抛出全局错误。
6、局限性
- 顺序错误处理
- 单一值
- 单决议
- 惯性
- 无法取消的Promise
- Promise性能