实现 Promise 代码的核心逻辑
- Promise 就是一个类,在执行这个类的时候需要传递一个执行器进去,这个执行器会立即执行
- Promise 中有三种状态,分别为 成功 fulfilled 失败 rejected 等待 pending
pending -> fulfilled
pending -> rejected
- resolve 和 reject 函数就是用来更改状态的
resolve: fulfilled
reject: rejected
- then 方法:
判断状态,若状态为成功,调用成功回调函数
如果状态为失败,调用失败回调函数
then 方法是被定义在原型对象中的
- then 成功回调有一个参数,表示成功后的值
then 失败回调有一个参数,表示失败的原因
- Promise 中加入异步调用 setTimeout 时,then 会比 setTimeout 先调用
此时调用 .then 方法时,还没有调用 resolve 和 reject 方法,状态为 pending
将成功回调和失败回调存储起来
异步调用执行完成后,调用 resolve 或 reject 时,调用之前存储的成功回调和失败回调
- then 方法多次调用
每一个 then 方法中传递的回调函数都要被执行
每一个 then 方法中传递的回调函数都要被存储起来
异步调用执行完成后,调用 resolve 或 reject 时,依次调用之前存储回调函数
- then 方法是可以被链式调用的,后面 then 方法的回调函数拿到的值是上一个 then 方法的回调函数的返回值
then 方法的链式调用 --> 返回 Promise 对象
拿到上一个 then 方法的回调函数的结果
- 如果 then 返回的是一个 Promise 对象,要判断状态,决定调用 resolve 还是 reject
- then 方法链式调用识别 Promise 对象自返回
报出错误 Chaining cycle detected for promise #
- 捕获错误
执行器当中的代码执行过程中发生错误时,状态变为错误状态
then 方法中的回调函数在执行过程中发生错误时,要在下一个 then 方法中报出错误
- 将 then 方法的参数变为可选参数
promise
.then() // .then(value => value)
.then()
.then(value => console.log(value))
- Promise.all
静态方法,参数为一个数组
- Promise.resolve
静态方法,返回一个 promise 对象,参数为普通值或 promise 对象
- finally
无论当前 promise 对象最终是成功还是失败,都会被调用
后面可以用 then 方法,得到最终的值
定义在原型对象上
finally 方法的回调函数中可以 return 一个 promise 对象,此时应该等待这个 promise 对象执行完成之后,再执行下一个 then
- catch
定义在原型对象上
catch (failCallback) {
return this.then(undefined, failCallback)
}
实现代码:
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor (executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING
value = undefined
reason = undefined
successCallback = []
failCallback = []
resolve = value => {
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = value
while (this.successCallback.length) this.successCallback.shift()()
}
reject = reason => {
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
while (this.failCallback.length) this.failCallback.shift()()
}
then (successCallback, failCallback) {
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : reason => { throw reason }
const promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
const x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
const x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else {
this.successCallback.push(() => {
setTimeout(() => {
try {
const x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.failCallback.push(() => {
setTimeout(() => {
try {
const x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
finally (callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => {throw reason})
})
}
catch (failCallback) {
return this.then(undefined, failCallback)
}
static all (array) {
const result = []
let index = 0
return new Promise((resolve, reject) => {
const addData = (key, value) => {
result[key] = value
index++
if (index === array.length) {
resolve(result)
}
}
for (let i = 0; i < array.length; i++) {
let current = array[i]
if (current instanceof MyPromise) {
current.then(value => addData(i, value), reason => reject(reason))
} else {
}
}
resolve()
})
}
static resolve (value) {
if (value instanceof MyPromise) return value
return new MyPromise(resolve => resolve(value))
}
}
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}
module.exports = MyPromise