说明
由于手写实现Promise无法区别宏任务与微任务,因此这里的实现源码只是为了理解。
Promise规范要点
- Promise是一个类,接收一个函数作为参数,该函数称为执行器,创建Promise对象时,执行器会立刻执行;
- Promise有三种状态,分别为pending等待、fulfilled成功、rejected失败;其中pending会转换为fulfilled或者rejected,一旦状态更新,则无法再更新状态;
- 执行器函数接收两个参数,分别为resolve函数和reject函数,只是用于更新Promise对象的状态,并可以将数据传递下去;reject的参数并不是错误,只有用throw语句才会抛出错误。抛出错误的时候,由执行器函数或回调函数内部的try-catch语句来捕获。由于我们的reject函数放在了catch语句里,因此then方法的rejected回调函数使用throw来向下传递数据。
- then()方法内部需要判断状态,状态成功则调用onFulfilled函数,状态失败则调用onRejected函数。
- 异步情况的处理,需要存储then方法内部的回调函数,在异步任务结束时,调用resolve或reject后,同时调用相应的回调函数
// 定义状态常量,在编辑器中可以得到代码提示信息;
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
// try-catch捕获执行器异常
try {
executor(this.resolve, this.reject);
} catch(e) {
this.reject(e);
}
}
// 定义实例属性,用于表示Promise的状态
_status = PENDING;
// 成功之后的值
_value = undefined;
// 失败之后的值
_err = undefined;
// 用于存储成功回调函数的队列,实现给同一个Promise用then()注册多个回调函数
onSuccess = [];
// 用于存储失败回调函数的队列,实现给同一个Promise用then()注册多个回调函数
onFail = [];
// 之所以定义为箭头函数,是为了在使用resolve()调用时,内部的this指向MyPromise的实例
resolve = (value) => {
// 判断状态,如果不是PENDING,则返回;
if(this._status !== PENDING) return;
// 更新状态
this._status = FULFILLED;
// 保存value值
this._value = value;
// 判断成功回调是否存在,如果存在,则调用
// this.onSuccess && this.onSuccess(this._value);
while(this.onSuccess.length) {
this.onSuccess.shift()();
}
}
reject = (err) => {
// 判断状态,如果不是PENDING,则返回;
if(this._status !== PENDING) return;
// 更新状态
this._status = REJECTED;
// 保存err
this._err = err;
// 判断失败回调是否存在,如果存在,则调用
// this.onFail && this.onFail(this._err);
while(this.onFail.length) {
this.onFail.shift()();
}
}
// 实现then方法
then(successCallback, failCallback) {
// 解决then()方法可选参数的问题;
successCallback = successCallback ? successCallback: value => value;
// 用throw语句将异常传递下去,throw语句用来抛出异常,可以将throw关键字后面表达式的值抛出
failCallback = failCallback ? failCallback: err => { throw err; }
// 创建一个Promise对象并返回,实现链式调用;
let my_promise = new MyPromise((resolve, reject) => {
// 判断状态
if(this._status === FULFILLED) {
setTimeout(() => {
// 捕获回调函数中的异常
try {
// 创建变量来接收成功回调函数的返回值;
let x = successCallback(this._value);
// 判断x值是否是Promise对象,如果是普通值,则直接resolve或reject
// 否则需要查看Promise对象的值,再调用resolve或reject
// 调用resolvePromise(),将x的值传递出去;
// 由于三种状态下都需要用到这个函数,所以这里的resolvePromise()方法抽象为公共函数
// 传入my_promise是为了对比my_promise与x是否相同,相同则表示出现Promise循环调用,需要抛出异常
// my_promise对象无法在同步的情况下拿到
// 因此将整个代码放到setTimeout()中来获取my_promise对象
resolvePromise(my_promise, x, resolve, reject);
} catch(e) {
reject(e);
}
}, 0);
} else if(this._status === REJECTED) {
setTimeout(() => {
try {
let x = failCallback(this._err);
resolvePromise(my_promise, x, resolve, reject);
} catch(e) {
reject(e);
}
}, 0);
} else {
// 处理异步情况,此时为PENDING状态,就将成功状态和失败状态的回调函数存储起来
this.onSuccess.push(() => {
setTimeout(() => {
try {
let x = successCallback(this._value);
} catch(e) {
reject(e);
}
}, 0);
});
this.onFail.push(() => {
setTimeout(() => {
try {
let x = failCallback(this._value);
} catch(e) {
reject(e);
}
}, 0);
});
}
});
return my_promise;
}
// 定义静态方法all()
static all(arr) {
// 声明一个数组,用来存储arr中所有操作的结果
let result = [];
// 声明一个变量index,用来判断是否所有异步操作都已完成,如果异步操作未完成,index值小于arr.length
let index = 0;
return new MyPromise((resolve, reject) => {
// 声明addData函数,用于将操作的结果存储到result数组
function addData(key, value) {
result[key] = value;
index ++;
if(index === arr.length) {
resolve(result);
}
}
for(let i = 0; i < arr.length; i ++) {
let current = arr[i];
if(current instanceof MyPromise) {
// 当前arr元素为Promise对象
current.then((value) => {
addData(value);
}, (err) => {
reject(err);
})
} else {
// 当前arr元素不是Promise对象
addData(i, arr[i]);
}
}
})
}
// 定义静态方法resolve
static resolve(value) {
// 如果传入的value是Promise对象,则原样返回,否则返回新的Promise对象,将value传递
if(value instanceof MyPromise) {
return value;
} else {
return new MyPromise((resolve) => {
resolve(value);
})
}
}
// 定义实例finally方法,不管Promise对象状态如何,finally的回调函数一定会执行
finally(callback) {
// 返回一个Promise对象
return this.then((value) => {
return MyPromise.resolve(callback()).then(() => value);
}, (err) => {
return MyPromise.resolve(callback()).then(() => { throw err; });
})
}
// 定义实例catch方法
catch(failCallback) {
// 调用then方法,只传递onRejected状态的回调即可
return this.then(undefined, failCallback);
}
}
function resolvePromise(my_promise, x, resolve, reject) {
if(my_promise === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
if(x instanceof MyPromise) {
// x是Promise对象,则调用then方法查看值,并利用resolve或reject传递
/* x.then((value) => {
resolve(value)
}, (err) => {
reject(err);
}); */
x.then(resolve, reject);
} else {
resolve(x);
}
}