1) Promise 基本特性
- Promise 有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。
- Promise 对象接受一个回调函数作为参数,该回调函数接受两个参数,分别是成功时的回调 resolve 和失败时的回调 reject;另外 resolve 的参数除了正常值以外,还可能是一个 Promise 对象的实例;reject 的参数通常是一个 Error 对象的实例。
- then 方法返回一个新的 Promise 实例,并接收两个参数 onResolved(fulfilled 状态的回调)、onRejected(rejected 状态的回调,该参数可选)。
- catch 方法返回一个新的 Promise 实例。
- finally 方法不管 Promise 状态如何都会执行,该方法的回调函数不接受任何参数。
- Promise.all() 方法将多个 Promise 实例包装成一个新的 Promise 实例,该方法接收一个由 Promise 对象组成的数组作为参数(Promise.all() 方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例),注意参数中只要有一个实例触发 catch 方法,都会触发 Promise.all() 方法返回新的 Promise 实例的 catch 方法,如果参数中的某个实例本身调用了 catch 方法,将不会触发 Promise.all() 方法返回的新的实例的 catch 方法。
- Promise.race() 方法的参数与 Promise.all() 方法一样,参数中的实例只要有一个率先改变状态就会将该实例的状态传给 Promise.race() 方法,并将该返回值作为 Promise.race() 方法产生的 Promise 实例的返回值。
- Promise.resolve() 将现有对象转为 Promise 对象,如果该方法的参数为一个 Promise 对象,Promise.resolve() 将不做任何处理;如果参数是一个 thenable 对象(即具有 then 方法),promise.resolve() 将该对象转为 Promise 对象并立即执行 then 方法;如果参数是一个原始值,或者是一个不具有 then 方法的对象,则 Promise.resolve() 方法返回一个新的 Promise 对象,状态为 fulfilled,其参数将会作为 then 方法中 onResolved 回调函数的参数;如果 Promise.resolve 方法不带参数,会直接返回一个 fulfilled 状态的 Promise 对象。需要注意的是,不带参数的情况下,返回的 Promise 对象是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。
- Promise.reject() 同样返回一个新的 Promise 对象,状态为 rejected,无论传入任何参数都将作为 reject() 的参数。
2)Promise 优点
- 统一异步 API
- Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API,统一现在各种各样的 API,以及不兼容的模式和手法。
- Promise 与事件对比
- 和事件相比较,Promise 更适合处理一次性的结果,在结果计算出来之前或之后注册回调函数都是可以的,都可以拿到正确的值。Promise 的这个优点很自然,但是不能使用 Promise 处理多次触发的事件。链式处理是 Promise 的又一优点,但是事件却不能这样链式处理。
- Promise 与回调对比
- 解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。
- Promise 带来的额外好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如 Array.prototype.map())。
3)Promise 缺点
- 无法取消 Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise 内部抛出的错误不回反应到外部。
- 当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
- Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。
4)简单代码实现
最简单的 Promise 实现有7个主要属性,state(状态)、value(成功返回值)、reason(错误信息)、resolve 方法、reject 方法、then 方法。
class Promise {
constructor(executor) {
this.state = 'pending'
this.value = undefined
this.reason = undefined
let resolve = value => {
if(this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
}
}
let reject = reason => {
if(this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
}
}
try {
// 立即执行函数
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
if(this.state === 'fulfilled') {
onFulfilled(this.value)
} else if(this.state === 'rejected') {
onRejected(this.reason)
}
}
}
5)面试够用版
function myPromise(constructor) {
let self = this
self.status = 'pending' // 定义状态改变前的初始状态
self.value = undefined // 定义状态为 resolved 的时候的状态
self.reason = undefined // 定义状态为 rejected 的时候的状态
function resolve(value) {
// 两个 === 'pending',保证了状态的改变是不可逆的
if(self.status === 'pending') {
self.value = value
self.status = 'resolved'
}
}
function reject(reason) {
// 两个 === 'pending',保证了状态的改变是不可逆的
if(self.status === 'pending') {
self.value = reason
self.status = 'rejected'
}
}
// 捕获构造异常
try {
constructor(resolve, reject)
} catch(e) {
reject(e)
}
}
myPromise.prototype.then = function(onFulfilled, onRejected) {
let self = this
switch(self.status) {
case 'resolved':
onFulfilled(self.value)
break
case 'rejected':
onRejected(self.reason)
break
}
}
// 测试
var p = new myPromise(function(resolve) { resolve(1) })
p.then(function(res) { console.log(res) })
// 输出1