Promise1.0版本⭐Promise类的实现是高级面试中常考的题目,由于Promise包含的方法比较多,一般写到Promise1.0或者2.0版本已经能够满足面试要求了,不过全面深入理解Promise对于工作中Promise的使用也非常有帮助
Promise是一个类,要创建对象就要调用new关键字,传入的参数为一个函数executorexecutor函数有两个入参,为两个回调函数resolve,reject,它们已经在Promise类内部实现好了executor函数传入之后会被立即执行实现constrcutor函数,then函数
class MyPromise {
// 构造函数
constructor(executor) {
const resolve = (value) => {
this.value = value;
};
const reject = (reason) => {
this.reason = reason;
};
// 立即执行函数
executor(resolve, reject);
}
}
then基本实现
class MyPromise {
constructor(executor) {
const resolve = (value) => {
this.value = value;
};
const reject = (reason) => {
this.reason = reason;
};
executor(resolve, reject);
}
// then方法
then(onFulfilled, onRejected) {
onFulfilled(this.value);
onRejected(this.reason);
}
}
/* ---------------- 测试代码 ----------------------*/
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve("resolve value");
reject("reject reason");
}, 100);
});
promise.then(
(res) => { console.log("res:", res); },
(err) => { console.log("err:", err); }
);
// undefined undefined
❎问题:顺序执行到then方法时,setTimeout函数还没执行回调,this.value和this.reason还没为undefined
✅改进:onFulfilled(this.value)
和 onRejected(this.reason)
入参不应该在then方法中调用,应该在resolve和reject中调用
每次对代码改进的关键步骤都用⭐进行了标识
class MyPromise {
constructor(executor) {
const resolve = (value) => {
this.value = value;
this.onFulfilled(this.value); // ⭐
};
const reject = (reason) => {
this.reason = reason;
this.onRejected(this.reason); // ⭐
};
executor(resolve, reject);
}
// then方法
then(onFulfilled, onRejected) {
this.onFulfilled = onFulfilled; // ⭐
this.onRejected = onRejected; // ⭐
}
}
/* ---------------- 测试代码 ----------------------*/
const promise = new MyPromise((resolve, reject) => {
resolve("resolve value");
reject("reject reason");
});
promise.then(
(res) => { console.log("res:", res); },
(err) => { console.log("err:", err); }
);
// 报错:TypeError: this.onFulfilled is not a function
❎问题:调用this.onFulfilled时,还没执行到then,所以还是undefined
✅改进:必须更改顺序,先执行then,拿到回调函数,然后再在resolve、reject函数中调用回调函数
⭐重点:queueMicrotask()
主动调用异步函数,来更改代码的执行顺序
class MyPromise {
// 构造函数
constructor(executor) {
const resolve = (value) => {
this.value = value;
queueMicrotask(() => this.onFulfilled(this.value));// ⭐
};
const reject = (reason) => {
this.reason = reason;
queueMicrotask(() => this.onRejected(this.reason));// ⭐
};
executor(resolve, reject);
}
// then方法
then(onFulfilled, onRejected) {
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
}
}
❎问题:resolve和reject只能执行一个
✅改进:引入Promise状态变量
⭐重点:对于三种固定的状态,一般使用枚举来书写(ts),没有枚举就定义常量
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
class MyPromise {
// 构造函数
constructor(executor) {
this.status = PROMISE_STATUS_PENDING;
const resolve = (value) => {
if (this.status !== PROMISE_STATUS_PENDING) return; // ⭐
this.status = PROMISE_STATUS_FULFILLED;
this.value = value;
queueMicrotask(() => {
this.onFulfilled(this.value);
});
};
const reject = (reason) => {
if (this.status !== PROMISE_STATUS_PENDING) return; //⭐
this.status = PROMISE_STATUS_REJECTED;
this.reason = reason;
queueMicrotask(() => {
this.onRejected(this.reason);
});
};
executor(resolve, reject);
}
then(onFulfilled, onRejected) {
this.onFulfilled = onFulfilled;
this.onRejected = onRejected;
}
}
Promise2.0版本⭐
then多次调用
/* ---------------- 测试代码 ----------------------*/
const promise = new MyPromise((resolve, reject) => {
resolve("resolve value");
reject("reject reason");
});
promise.then(
(res) => { console.log("res:", res); },
(err) => { console.log("err:", err); }
);
promise.then(
(res) => { console.log("res1:", res); },
(err) => { console.log("err1:", err); }
);
// 宏任务在微任务之后,数组已经遍历执行结束了,怎么办
setTimeout(() => {
promise.then(
(res) => { console.log("res2:", res); },
(err) => { console.log("err2:", err); }
);
}, 100);
❎问题:
1 由于this.onFulfilled函数赋值是异步进行的,所以顺序执行的最后一个then方法会覆盖之前的,将自己的回调onFulfilled赋值给this.onFulfilled函数
2 若then回调是在异步函数中,在微任务之后,无法加入回调函数队列中执行
✅改进:
1 采用数组存取回调函数
2 在微任务之后,说明已经拿到了this.value和this.reason,那么回调函数在then函数中直接执行即可
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
class MyPromise {
// 构造函数
constructor(executor) {
this.status = PROMISE_STATUS_PENDING;
this.onFulfilledFns = [];//⭐ 数组保存
this.onRejectedFns = [];
const resolve = (value) => {
if (this.status !== PROMISE_STATUS_PENDING) return;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return; //⭐ 防止resolve和reject都执行
this.value = value;
this.onFulfilledFns.forEach((fn) => fn(this.value));
this.status = PROMISE_STATUS_FULFILLED;
});
};
const reject = (reason) => {
if (this.status !== PROMISE_STATUS_PENDING) return;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.reason = reason;
this.onRejectedFns.forEach((fn) => fn(this.reason));
this.status = PROMISE_STATUS_REJECTED;
});
};
executor(resolve, reject);
}
then(onFulfilled, onRejected) {
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
onFulfilled(this.value); //⭐状态已经确定,说明微任务执行完毕,this.value已经有值,直接执行就可以
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
onRejected(this.reason);
}
if (this.status === PROMISE_STATUS_PENDING) {
onFulfilled && this.onFulfilledFns.push(onFulfilled);//⭐ 加入数组
onRejected && this.onRejectedFns.push(onRejected);
}
}
}
then链式调用
then能链式调用,说明then函数能够返回一个Promise对象
⭐重点:
1 如何拿到回调函数的结果?再包裹一层回调函数
2 reject的函数的返回值也是一个Promise对象,和resolve没有区别
3 如果要在reject抛出出错,需要用try-catch捕获
// 工具函数
function execFunctionWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value);
resolve(result);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
//⭐ then返回一个MyPromise对象
return new MyPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
}
if (this.status === PROMISE_STATUS_PENDING) {
//⭐push到数组的函数外层又包裹了一个回调函数,为了得到返回结果
onFulfilled &&
this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
});
onRejected &&
this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
});
}
});
}
Promise3.0版本
catch方法实现catch对象方法,finally对象方法
基于then方法实现,由于catch是在then后调用,实质上是then返回的promise对象调用的then方法,为了捕获原始的promise对象抛出的reject,需要将错误抛出
then(onFulfilled, onRejected) {
onRejected = onRejected || (err=> {throw new Error(err)}); // 将错误抛出去
return new MyPromise((resolve, reject) => {
/*原来代码*/
});
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally方法
finally(onFinally) {
return this.then(onFinally, onFinally);
}
Promise4.0版本
实现类静态方法resolve、reject
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value);
});
}
static reject(reason) {
return new MyPromise((resoble, reject)=>{
reject(reason);
})
}
Promise5.0版本
实现类方法all allSettled race any
⭐重点:什么时机调用resolve和reject
all static all(promises) {
const results = [];
let i = 0;
// 如何让保存取结果与顺序有关,与返回顺序无关
return new MyPromise((resolve, reject) => {
promises.forEach((p, index) => {
p.then(
(res) => {
results[index] = res;
i++;
if (i === promises.length) {
resolve(results);
}
},
(err) => {
reject(err);
}
);
});
});
}
allSettled
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let i = 0;
promises.forEach((p, index) => {
p.then(
(res) => {
results[index] = { status: PROMISE_STATUS_FULFILLED, value11: res };
i++;
if (i === promises.length) {
resolve(results);
}
},
(err) => {
results[index] = { status: PROMISE_STATUS_REJECTED, reason: err };
i++;
if (i === promises.length) {
resolve(results);
}
}
);
});
});
}
race
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
resolve,
reject
);
});
});
}
any
static any(promises) {
return new MyPromise((resolve, reject) => {
const reasons = [];
promises.forEach((promise) => {
promise.then(
(res) => {
resolve(res);
},
(err) => {
reasons.push(err);
if (reasons.length === promises.length) {
reject(reasons);
}
}
);
});
});
}
代码整合
const PROMISE_STATUS_PENDING = "pending";
const PROMISE_STATUS_FULFILLED = "fulfilled";
const PROMISE_STATUS_REJECTED = "rejected";
function execFunctionWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value);
resolve(result);
} catch (err) {
reject(err);
}
}
class MyPromise {
// 构造函数
constructor(executor) {
this.status = PROMISE_STATUS_PENDING;
this.onFulfilledFns = [];
this.onRejectedFns = [];
const resolve = (value) => {
if (this.status !== PROMISE_STATUS_PENDING) return;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.value = value;
this.onFulfilledFns.forEach((fn) => fn(this.value));
this.status = PROMISE_STATUS_FULFILLED;
});
};
const reject = (reason) => {
if (this.status !== PROMISE_STATUS_PENDING) return;
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return;
this.reason = reason;
this.onRejectedFns.forEach((fn) => fn(this.reason));
this.status = PROMISE_STATUS_REJECTED;
});
};
executor(resolve, reject);
}
then(onFulfilled, onRejected) {
onRejected =
onRejected ||
((err) => {
throw new Error(err);
});
onFulfilled = onFulfilled || ((value) => value);
return new MyPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
}
if (this.status === PROMISE_STATUS_REJECTED) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
}
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject);
});
this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject);
});
}
});
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
finally(onFinally) {
return this.then(onFinally, onFinally);
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value);
});
}
static reject(reason) {
return new MyPromise((resoble, reject) => {
reject(reason);
});
}
static all(promises) {
const results = [];
let i = 0;
return new MyPromise((resolve, reject) => {
promises.forEach((p, index) => {
p.then(
(res) => {
results[index] = res;
i++;
if (i === promises.length) {
resolve(results);
}
},
(err) => {
reject(err);
}
);
});
});
}
static allSettled(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let i = 0;
promises.forEach((p, index) => {
p.then(
(res) => {
results[index] = { status: PROMISE_STATUS_FULFILLED, value11: res };
i++;
if (i === promises.length) {
resolve(results);
}
},
(err) => {
results[index] = { status: PROMISE_STATUS_REJECTED, reason: err };
i++;
if (i === promises.length) {
resolve(results);
}
}
);
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(resolve, reject);
});
});
}
static any(promises) {
return new MyPromise((resolve, reject) => {
const reasons = [];
promises.forEach((promise) => {
promise.then(
(res) => {
resolve(res);
},
(err) => {
reasons.push(err);
if (reasons.length === promises.length) {
reject(reasons);
}
}
);
});
});
}
}
// 使用
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
// resolve("resolve value");
reject("reject reason");
}, 100);
});
promise
.then((res) => {
console.log("res:", res);
return "aaa";
})
.catch((err) => {
console.log("err:", err);
});
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)