// 1、自己使用javascript手写一个Promise类,
// 2、实现原型方法then/catch/finally,
// 3、实现静态方法resolve/reject。
// 4、实现原型方法all/race
// ES6实现方法
class iPromise {
constructor(executor) {
// 存储promise结果
this.promiseResult = undefined;
// 存储promise的状态
this.promiseState = 'pending';
// 存储所有的回调函数
this.callbackList = [];
// resolve方法,将promiseState变为fulfilled,并修改promiseResult
const resolve = (value) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
//添加微任务
queueMicrotask(() => {
// 将promiseState变为fulfilled
this.promiseState = 'fulfilled';
// 将value作为promiseResult
this.promiseResult = value;
// 异步执行所有回调函数
this.callbackList.forEach(cb => cb.onResolved(value));
});
}
// reject方法,将promiseState变为rejected,并修改promiseResult
const reject = (error) => {
// 仅在promiseState为pending的时候变化
if (this.promiseState !== 'pending') return;
//添加微任务
queueMicrotask(() => {
// 将promiseState变为rejected
this.promiseState = 'rejected';
// 将error作为promiseResult
this.promiseResult = error;
// 异步执行所有回调函数
this.callbackList.forEach(cb => cb.onRejected(error));
});
}
// 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】
try {
/*
* 同步执行执行器函数
* 执行器函数接收两个参数,一个是resolve,一个是reject
*/
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
// 接收两个回调函数作为参数
then(onResolved, onRejected) {
//处理异常穿透并且为onResolved,onRejected设置默认值。因为这两个参数可以都不传
if (typeof onRejected !== 'function') {
onRejected = err => {
throw err;
}
}
if (typeof onResolved !== 'function') {
onResolved = val => val;
}
/*
* 这里必须要写箭头函数,否则this会指向新的Promise对象
* 进而导致取不到promiseState和promiseResult
*/
return new iPromise((resolve, reject) => {
/*
* 回调处理函数
* 这里也请记得用箭头函数,this要穿透几层
* 箭头函数就用几层
*/
const handleCallback = (callback) => {
try {
let res = callback(this.promiseResult);
// 若返回值是promise对象
if (res instanceof iPromise) {
res.then(val => resolve(val), err => reject(err));
} else {
// 若不是
resolve(res);
}
} catch (error) {
reject(error);
}
}
// promiseState为fulfilled时调用onResolved
if (this.promiseState === "fulfilled") {
setTimeout(() => {
handleCallback(onResolved);
});
}
// promiseState为rejected时调用onRejected
if (this.promiseState === "rejected") {
setTimeout(() => {
handleCallback(onRejected);
});
}
/*
* 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数
* 所以要保存回调函数
* 因为promise实例可以指定多个回调,于是采用数组
*/
if (this.promiseState === "pending") {
this.callbackList.push({
onResolved: () => {
handleCallback(onResolved)
},
onRejected: () => {
handleCallback(onRejected)
}
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinally) {
//不管成功或者失败都要调用finally
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new iPromise((resolve, reject) => {
if (value instanceof iPromise) {
value.then(val => resolve(val), err => reject(err));
} else {
resolve(value)
}
})
}
static reject(error) {
return new iPromise((resolve, reject) => {
reject(error);
})
}
static all(promiseArrays) {
return new iPromise((resolve, reject) => {
// 用以存储执行的结果
let results = [];
let length = promiseArrays.length;
promiseArrays.forEach((promiseObj, index, promiseArrays) => {
promiseObj.then((val) => {
results.push(val);
// 由于是多个异步任务的关系,需要判断是否都执行完毕
if (results.length === length) {
resolve(results);
}
}, err => {
// 如有错误,则reject
reject(err);
});
})
})
}
static race(promiseArrays) {
return new iPromise((resolve, reject) => {
promiseArrays.forEach(promiseObj => {
promiseObj.then(val => {
resolve(val);
}, err => {
reject(err);
});
});
})
}
}
面试题:如何手写一个Promise(详细版)
最新推荐文章于 2024-07-28 21:22:56 发布