实现MyPromise
分析Promise原理
- 首先Promise是使用new来进行初始化,所以Promise是一个类
- 在初始化的时候我们需要传入一个函数进去,并且这个函数是理解执行的
- 初始化传入的函数有两个参数,这两个参数都是函数类型,分别为:resolve、reject,这两个函数是用来改变Promise状态的
- Promise有三种状态,分别为pending、fulfilled、rejected
- Promise的状态可以发生变化,但是变化是由规则的即pending状态可以变化为fulfilled或rejected状态,一旦变化后不能改变
- Promise有一个then方法,这个方法有两个参数,但是是可选的,第一个参数用于处理成功的回调,这个回调会传入成功的值;第二个参数是失败的回调,这个回调会传入失败的原因
- then方法内部做状态判断,如果状态是成功就调用传入的成功回调,如果状态是失败就调用失败的回调
- 同一个Promise对象下面的then方法是可以被调用多次的
- then方法是可以被链式调用的,后面的then方法的回调函数拿到的值是上一个then方法的回调函数的返回值
- Promise具有静态方法all、resolve、finally
- Proimse具有异常捕捉方法catch
示例:
// 常量状态
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class MyPromise {
// 构造函数
constructor(exexutor) {
// 传入的函数又叫执行器,这个执行器会被立即执行
// 当运行执行器时内部出现错误,直接捕获并通过reject方法返回给外部
try {
exexutor(this.resolve, this.reject)
} catch(e) {
// 出现异常直接调用reject
this.reject(e)
}
}
// 由于状态我们需要在其他地方使用,所以讲状态保存为实例
status = PENDING // 初始值为PENDING
// 当then方法传入的回调是异步时,我们需要先将resolve和reject的值存储起来
value = undefined
error = undefined
// 当then方法传入的回调是异步调用或者then被多次调用时需要将传入的回调存储起来
successCallback = []
failCallback = []
// 处理成功回调的方法
resolve = value => {
// 因为执行器中不能同时执行resolve和reject,所以我们需要在做状态更改之前先判断状态
if (this.status !== PENDING) return
// 将状态更改为FULFILLED
this.status = FULFILLED
// 保存成功之后的值
this.value = value
// 判断成功回调是否存在,如果存在则调用并且兼容多次then调用
while(this.successCallback.length) this.successCallback.shift()()
}
// 处理失败回调的方法
reject = error => {
// 处理方法同resolve类似
if (this.status != PENDING) return
this.status = REJECTED
this.value = value
while(this.failCallback.length) this.failCallback.shift()()
}
// then方法
then(successCallback, failCallback) {
// 因为then的参数是可选的,所以判断下当没有传入参数时处理下
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : error => { throw error }
// then方法支持链式调用,所以我们需要返回一个新的Promise对象
let promise2 = new Promise((resolve, reject) => {
// 新返回的也需要先判断状态
if (this.status === FULFILLED) {
// 变为异步,否则拿不到promise2
setTimeout(() => {
try {
let x = successCallback(this.value)
// 此处需要判断下x是普通值还是Promise对象
// 如果是普通值,直接调用resolve
// 如果是peomise对象,需要查看Promise对象的返回结果决定调用resolve还是reject
// 由于这个方法需要多次调用,封装起来
resolvePromise(promsie2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
} else if (this.status == REJECTED) {
// 处理同resolve
setTimeout(() => {
try {
let x = failCallback(this.error);
resolvePromise(promsie2, x, resolve, reject)
}catch (e) {
reject(e);
}
}, 0)
} else {
// 处理异步情况当前状态是PENDING
// 将回调存储起来
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promsie2, x, resolve, reject)
}catch (e) {
reject(e)
}
}, 0)
});
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.error)
resolvePromise(promsie2, x, resolve, reject)
}catch (e) {
reject(e)
}
}, 0)
})
}
})
// 返回promise2
return promise2
}
// 实现finally
// 执行完成后无论成功还是失败都会执行
finally (callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value);
}, error => {
return MyPromise.resolve(callback()).then(() => { throw error })
})
}
//catch,没有resolve方法的then
catch (failCallback) {
return this.then(undefined, failCallback)
}
// 静态resolve
static resolve (value) {
// 如果value是当前实例直接返回
if (value instanceof MyPromise) return value;
// 如果不是,那就包装下
return new MyPromise(resolve => resolve(value));
}
// 静态all方法
static all (array) {
// 存储执行结果
let result = [];
// 标识传入数组的操作是否都执行完成
let index = 0;
return new MyPromise((resolve, reject) => {
function 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) {
// promise 对象
current.then(value => addData(i, value), error => reject(error))
}else {
// 普通值
addData(i, array[i]);
}
}
})
}
}
function resolvePromise(promsie2, x, resolve, reject) {
// 此处判断避免循环调用自己
if (promsie2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (x instanceof MyPromise) {
x.then(resolve, reject)
} else {
resolve(x)
}
}