手写Promise
Posted 还是不会呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写Promise相关的知识,希望对你有一定的参考价值。
手写Promise
手写Promise代码
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";
// 对resolve里的回调函数进行监听抛出错误的同时,需要对回调函数的返回值进行判断
// 参考原生Promise返回值的三种情况
function fulfilledFunctionThrowErr(onfulfilled, query, resolve, reject) {
try {
const result = exceFn(query);
if (result instanceof MsiPromise || "then" in result) {
result.then((res) => {
resolve(res);
});
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
// 但是reject内的回调函数返回值却没有这样的区别,返回什么类型就是什么类型
function rejectededFunctionThrowErr(onrejected, query, resolve, reject) {
try {
const result = exceFn(query);
resolve(result);
} catch (error) {
reject(error);
}
}
class MsiPromise {
constructor(executor) {
// 用于保存当前Promise对象的状态
this.status = PROMISE_STATUS_PENDING;
// 因为同一个Promise可以使用多个then和catch方法的回调函数,那么需要将其保存起来
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
// resolve函数
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.value = value;
// 微任务队列,如果不使用那么此时,代码是还没有执行到then那一步去的,
// 对应的回调函数也是无法放入到数组内,使用微任务队列,涉及到事件循环[后面将会讲到]
queueMicrotask(() => {
// 之所以会有下面两句,因为微任务队列代码稍后执行,若创建Promise的回调函数内都调用了resolve和reject
// 本应该是先写到那个就执行那个,并且状态改变后且不可再改变,那么resolve,reject函数内的微任务队列内的回调函数
// 都将加入微任务队列,那么就有下面第一句,不是pending状态直接返回,这样就可以执行一次
if (this.status !== PROMISE_STATUS_PENDING) return;
this.status = PROMISE_STATUS_FULFILLED;
this.onFulfilledCallbacks.forEach((fn) => {
fn(this.value);
});
});
}
};
// reject函数
const reject = (reason) => {
if (this.status !== PROMISE_STATUS_PENDING) return;
if (this.status === PROMISE_STATUS_PENDING) {
this.reason = reason;
queueMicrotask(() => {
this.status = PROMISE_STATUS_REJECTED;
this.onRejectedCallbacks.forEach((fn) => {
fn(this.reason);
});
});
}
};
// 创建Promise对象时,传入的回调函数,是直接执行的
// 同时也可以在该回调函数内抛出错误,在catch回调内捕获到,就需要try...catch进行捕获
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onfulfilled, onrejected) {
// 之所以要进行这样一层判断,因为catch方法,finally方法都是基于then方法实现的
// 对于如下情况:
// new MsiPromise((resolve,reject)=>{reject("err message") }).then(res=>{ }).catch(err=>{})
// catch和前面的then是隶属于不同的promsie对象,也就是需要再then内将 第一个promise对象错误抛出,
// 才能在 catch内捕获到错误,同理也需要将 fulfilled的值直接返回给下一个promise
onrejected =
onrejected ??
((err) => {
throw err;
});
onfulfilled = onfulfilled ?? ((res) => res);
// then的返回值其实也是一个Promsie对象
return new MsiPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED) {
// 这是再加入数组内的函数已经执行之后,又出现一个then方法内的回调
// 那么此时不需要再加入对应数组内,直接执行就行了
fulfilledFunctionThrowErr(onfulfilled, this.value, resolve, reject);
}
if (this.status === PROMISE_STATUS_REJECTED) {
rejectededFunctionThrowErr(onrejected, this.reason, resolve, reject);
}
if (this.status === PROMISE_STATUS_PENDING) {
this.onFulfilledCallbacks.push(() => {
fulfilledFunctionThrowErr(onfulfilled, this.value, resolve, reject);
});
this.onRejectedCallbacks.push(() => {
rejectededFunctionThrowErr(onrejected, this.reason, resolve, reject);
});
}
});
}
catch(onrejected) {
return this.then(undefined, onrejected);
}
finally(onfinally) {
this.then(onfinally, onfinally);
}
static resolve(res) {
return new MsiPromise((resolve) => {
resolve(res);
});
}
static reject(reason) {
return new MsiPromise((resolve) => {
resolve(reason);
});
}
static all(promises) {
return new MsiPromise((resolve, reject) => {
const result = [];
promises.forEach((promise) => {
promise.then(
(res) => {
result.push(res);
if (result.length === promises.length) {
resolve(result);
}
},
(err) => {
reject(err);
}
);
});
});
}
static allSettled(promises) {
return new MsiPromise((resolve, reject) => {
const result = [];
promises.forEach((promise) => {
promise.then(
(res) => {
result.push({ status: "fulfilled", value: res });
if (promises.length === result.length) {
resolve(result);
}
},
(reason) => {
result.push({ status: "rejected", value: reason });
if (promises.length === result.length) {
reject(result);
}
}
);
});
});
}
static any(promises) {
return new MsiPromise((resolve, reject) => {
const result = [];
promises.forEach((promise) => {
promise.then(
(res) => {
resolve(res);
},
(reason) => {
result.push(reason);
if (result.length === promises.length) {
reject(new AggregateError(result));
}
}
);
});
});
}
static race(promises) {
return new MsiPromise((resolve) => {
promises.forEach((promise) => {
promise.then(
(res) => {
resolve(res);
},
(reason) => {
resolve(reason);
}
);
});
});
}
}
// 测试代码
MsiPromise.resolve("aaaa").then((res) => {
console.log(res);
});
MsiPromise.reject("aaaa").then((res) => {
console.log(res);
});
const p1 = new MsiPromise((resolve, reject) => {
setTimeout(() => {
resolve("aaaa");
}, 1000);
});
const p2 = new MsiPromise((resolve, reject) => {
setTimeout(() => {
reject("bbbb");
}, 2000);
});
const p3 = new MsiPromise((resolve, reject) => {
setTimeout(() => {
resolve("cccc");
}, 3000);
});
MsiPromise.all([p1, p2, p3])
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
过程思考
在完成上方代码时,发现不使用数组进行保存相应的回调函数,一样可以完成对于的功能,就是在resolve或reject时直接保存对应值,然后每次在then调用时直接传入相应值就行了,一样可以解决then方法延迟调用,并且创建Promise时resolve和reject同时存在只先执行一次得问题。
**但是:**then内得回调和catch内得回调函数并不是同步执行的,ES6中Promise确实也是异步执行的。
同步Promsie执行代码
const PROMISE_STATUS_FULFILLED = "PROMISE_STATUS_FULFILLED";
const PROMISE_STATUS_PENDING = "PROMISE_STATUS_PENDING";
const PROMISE_STATUS_REJECTED = "PROMISE_STATUS_REJECTED";
class MsiPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING;
this.value = null;
this.reason = null;
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED;
this.value = value;
}
};
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED;
this.reason = reason;
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onfulfilled, onrejected) {
onrejected =
onrejected ??
((err) => {
throw err;
});
onfulfilled = onfulfilled ?? ((res) => res);
return new MsiPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED) {
try {
const result = onfulfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
}
if (this.status === PROMISE_STATUS_REJECTED) {
try {
const error = onrejected(this.reason);
resolve(error);
} catch (error) {
reject(error);
}
}
});
}
catch(onrejected) {
return this.then(undefined, onrejected);
}
finally(onfinally) {
this.then(onfinally, onfinally);
}
}
// 测试代码
const promise = new MsiPromise((resolve, reject) => {
console.log("pending");
resolve("aaa");
});
promise.then((res) => {
console.log(res);
});
console.log("------------");
以上是关于手写Promise的主要内容,如果未能解决你的问题,请参考以下文章