前段时间面试时面试官问了我如何手写一个promise,心想只手写过promise的api,那如果直接手写promise应该从哪做起呢?
Promise结构&特性
结构:
1、Promise对象创建一个异步函数
2、异步函数中有resolve
、reject
两个函数参数
3、Promise中的fulfilled
、pending
、rejected
三种状态
4、Promise的.then
执行回调返回新的Promise
5、Promise的链式编程
特性:
1、主动抛出错误,会调用 reject()
方法回调。
2、.then
中传入非函数参数,不会报错。
实现思路
1、用class类或构造函数实现Promise对象。
2、自定义resolve
、reject
方法。
3、定义三种状态,且一旦确定后不可改变。
4. then 执行回调结果。
5. 异步执行:使用定时器执行 .then 回调。
6. 链式执行:让 .then 返回一个新的 Promise 来实现链式编程。
7. 使用 try-catch 来判断代码有无主动抛出一个错误。
8. 对 .then 中传入的参数进行非函数判断,如果不为函数则将其回调赋值为一个空对象。
实现
1、
class myPromise {
static PENDING = '待定';
static FULFILLED = '完成';
static REJECTED = '拒绝';
constructor(func) {
this.status = myPromise.PENDING;
this.result = null;
// 防止this丢失 创建实例后调用方法找不到this,使用bind绑定
//try catch 当出现错误时,把errormsg直接交给reject
//保存resolve 和 reject的回调
this.resolveCallbacks = [];
this.rejectCallbacks = [];
try {
func(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error)
}
}
//resolve方法
//resolve 和 reject是在事件循环末尾执行的 所以加上settimeout
resolve(result) {
setTimeout(() => {
if (this.status === myPromise.PENDING) {
this.status = myPromise.FULFILLED;
this.result = result;
this.resolveCallbacks.forEach(callback => {
callback(result)
})
}
});
}
//result方法
reject(result) {
setTimeout(() => {
if (this.status === myPromise.PENDING) {
this.status = myPromise.REJECTED;
this.result = result;
this.rejectCallbacks.forEach(callback => {
callback(result)
})
}
});
}
//then 方法
then(onFULFILLED, onREJECTED) {
//链式
return new myPromise((resolve,reject)=>{
onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : () => {};
onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => {};
if (this.status === myPromise.PENDING) {
this.resolveCallbacks.push(onFULFILLED);
this.rejectCallbacks.push(onREJECTED);
}
if (this.status === myPromise.FULFILLED) {
setTimeout(() => {
onFULFILLED(this.result);
})
}
if (this.status === myPromise.REJECTED) {
setTimeout(() => {
onREJECTED(this.result);
});
}
})
}
}
console.log(1);
let mp = new myPromise((resolve, reject) => {
console.log(2);
setTimeout(() => {
resolve('haha')
console.log(4);
});
})
mp.then((res) => {
console.log(res);
}, (err) => {
console.log(err);
})
console.log(3);