#### 手写Promise源码
// promise有三种状态 pending 等待 fulfilled 成功 rejected 失败
// 且状态改变只能从pending -> fulfilled(从等待到成功) 或者 pending -> rejected(从等待到失败) 且状态改变后不可更改
// 声明三种状态常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 创建Promise类
class MyProise {
// Promise 对象需要传入一个执行器函数 该执行器函数会立即执行 并且该执行器函数有两个参数成功回调 失败回调
// 并且两个参数resolve和reject是来更改函数状态的
// resolve -> fulfilled(从等待到成功)
// reject -> rejected(从等待到失败)
constructor(executor) {
// 使用trycatch是为了捕获执行器函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
try {
// 执行执行器函数 参数为更新函数状态的两个函数
executor(this.resolve, this.reject)
} catch (error) {
// 捕获执行器函数异常 将Promise类的函数状态更改为rejected
this.reject(error)
}
}
//记录函数状态并初始化函数状态为pending
status = PENDING
// 记录函数成功后的返回值 作为成功返回值给then方法成功回调
value = undefined
// 记录函数失败后的返回值 作为失败原因给then方法失败回调
reason = undefined
// 收集函数状态为成功的回调函数
successCallback = []
// 收集函数状态为失败的回调函数
failCallback = []
// 执行器成功函数
resolve = value => {
// 函数状态更改后不可改变 若函数状态不为等待 拒绝向下执行
if (this.status !== PENDING) return
// 将函数状态更改为成功
this.status = FULFILLED
// 成功后的返回值
this.value = value
// Promise函数具有thenable接口且可以多次调用 导致可能会有多个回调函数执行
// 使用while循环是因为数组变化导致循环体不成立时自动停止
while (this.successCallback.length) this.successCallback.shift()()
}
// 执行器失败函数
reject = reason => {
// 函数状态更改后不可改变 若函数状态不为等待 拒绝向下执行
if (this.status !== PENDING) return
// 将函数状态更改为失败
this.status = REJECTED
// 失败后的返回值
this.reason = reason
// Promise函数具有thenable接口且可以多次调用 导致可能会有多个回调函数执行
// 使用while循环是因为数组变化导致循环体不成立时自动停止
while (this.failCallback.length) this.failCallback.shift()()
}
// 类的thenable接口
then(successCallback, failCallback) {
// then方法具有thenable接口 可以链式调用 需要返回一个promise对象
// 创建Promise对象
let promise = new MyPromise((resolve, reject) => {
// then函数的状态取决于回调函数运行状态 现在判断状态
if (this.status === FULFILLED) {
// 状态为成功
// 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
// 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
setTimeout(() => {
// 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
try {
let result = successCallback(this.value)
// result的值可能存在两种情况普通值和promise对象
// 如果为普通值直接调用resolve返回
// 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
// 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
// 此逻辑我们用一个函数来实现 因此我们需要传入四个参数
// 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
resolvePromise(promise, result, resolve, reject)
} catch (error) {
// 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
reject(error)
}
}, 0)
} else if (this.status === REJECTED) {
// 状态为失败
// 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
// 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
setTimeout(() => {
// 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
try {
let result = failCallback(this.value)
// result的值可能存在两种情况普通值和promise对象
// 如果为普通值直接调用resolve返回
// 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
// 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
// 此逻辑我们用一个函数来实现 因此我们需要传入四个参数
// 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
resolvePromise(promise, result, resolve, reject)
} catch (error) {
// 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
reject(error)
}
}, 0)
} else {
// 状态为等待
// 此时需要等待then方法执行完毕才能直到函数状态
// 故将成功回调和失败回调存储起来 待状态更改之后在调用
this.successCallback.push(() => {
// 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
// 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
setTimeout(() => {
// 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
try {
let result = successCallback(this.value)
// result的值可能存在两种情况普通值和promise对象
// 如果为普通值直接调用resolve返回
// 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
// 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
// 此逻辑我们用一个函数来实现 因此我们需要传入四个参数
// 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
resolvePromise(promise, result, resolve, reject)
} catch (error) {
// 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
reject(error)
}
}, 0)
})
this.failCallback.push(() => {
// 在此逻辑中我们会用到变量promise 为确定变量promise有值 必须确定new MyPromise执行完毕
// 故我们使用定时器setTimeout 不是为了延迟而是为了异步执行以确定变量promise有值
setTimeout(() => {
// 使用trycatch是为了捕获函数中的运行异常 如出现异常则执行catch逻辑 将Promise类的函数状态更改为rejected并将失败原因返回
try {
let result = failCallback(this.value)
// result的值可能存在两种情况普通值和promise对象
// 如果为普通值直接调用resolve返回
// 如果为promise对象则根据promise的执行结果决定调用resolve还是reject
// 并且then方法返回的promise对象不能是当前then方法返回的对象, 否则会产生Promise对象的循环调用, JS会报错
// 此逻辑我们用一个函数来实现 因此我们需要传入四个参数
// 1. then方法返回值promise 2. then方法成功回调的返回值 3. 更改状态为成功resolve 4. 更改状态为失败reject
resolvePromise(promise, result, resolve, reject)
} catch (error) {
// 捕获函数异常 将Promise类的函数状态更改为rejected并将失败原因返回
reject(error)
}
}, 0)
})
}
})
// 返回then函数的promise对象
return promise
}
// 类的finally方法 参数为回调函数
// finally方法的内容都会被执行一次
// finally方法之后可以链式调用then方法
finally(callback) {
// 在finally 内部可以通过then方法拿到 当前promise的状态
// 并且then方法返回promise对象 可以链式调用then方法
return this.then(value => {
// 如果finally的回调函数是promise 需等待回调函数执行完成在将结果返回给之后的链式调用
return MyProise.resolve(callback()).then(() => value)
}, reason => {
// 如果finally的回调函数是promise 需等待回调函数执行完成在将结果返回给之后的链式调用
return MyProise.resolve(callback()).then(() => {throw reason})
})
}
// 捕获异常
catch(failCallback){
// 使用then方法去注册失败回调 并置空成功回调
return this.then(undefined, failCallback)
}
// promise.all()方法 参数为数组 返回结果为数组内的元素顺序(且为promise对象), 不论有无延迟
// 解决异步并发问题
static all(array){
// 声明结果数组 作为all方法的返回值
let result = []
// all方法中有可能有promise的异步操作, 为保证参数数组中每一项都有返回值 需对返回结果修改时进行标记(累加处理)
let index = 0
return new MyProise((resolve, reject) => {
// 将结果放入结果数组
function addData(key, value){
result[key] = value
// 累加处理
index++
// 当所有结果都有返回值时 执行all方法的成功回调
if(index === array.length){
resolve(result)
}
}
// 遍历当前数组 并且判断循环体是普通值还是promise对象
for(let i = 0; i < array.length; i++){
// 劫持循环体
let current = array[i]
if(current instanceof MyProise){
// 循环体为promise对象 根据其运行结果调用resolve和reject更改状态
current.then(value => addData(i, value), reason => reject(reason))
}else {
// 循环体为普通值
addData(i, current)
}
}
})
}
// Promise.resolve()方法返回一个promise对象
static resolve (value){
// 如果value是promise对象直接返回
if(value instanceof MyProise) return value
// 如果value是普通值 返回一个promise对象 并且将value当作成功返回值返回
return new MyProise(resolve => resolve(value))
}
}
function resolvePromise(promise, result, resolve, reject) {
// 如果then方法返回值promise 和 then方法成功回调的返回值 相同
if (promise === result) {
// 抛出错误 promise对象循环调用
return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
}
// 如果then方法成功回调的返回值 是promise对象
if (result instanceof MyProise) {
// 调用promise对象的then方法 根据执行结果决定调用resolve还是reject
result.then(resolve, reject)
} else {
// 如果then方法成功回调的返回值 是普通值
resolve(result)
}
}