前言
手写Promise
相关经常是各大公司手撕代码环节会被问到的问题,本文手把手带你实现一遍Promise
的核心功能和方法。
基础功能实现
const test = new Promise((reslove, reject) => {
reslove("siu");
});
test.then((res) => {
console.log(res); // siu
});
接下来实现这一部分功能
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class selfPromise {
constructor(exec) {
this.status = PENDING;
this.result = null;
// 用bind绑定this或resolve和reject用箭头函数 让它绑定到实例
exec(this.resolve.bind(this), this.reject.bind(this));
}
resolve(result) {
// 只有在PENDING状态下,才需要改变状态和记录结果
// 这样也保证了Promise状态一旦改变就不能再改变
// reject和reslove相同
if (this.status === PENDING) {
this.status = FULFILLED;
this.result = result;
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED;
this.result = reason;
}
}
then(onFULFILLED, onREJECTED) {
if (this.status === FULFILLED) {
onFULFILLED(this.result);
}
if (this.status === REJECTED) {
onREJECTED(this.result);
}
}
}
const test = new selfPromise((resolve, reject) => {
resolve("siu is good");
// reject("reject is good");
});
test.then(
(res) => {
console.log(res); // siu is good
},
(rej) => {
console.log(rej); //reject is good
}
);
实现异步逻辑和抛出错误
const test = new selfPromise((resolve, reject) => {
setTimeout(() => {
resolve("siu is good");
});
// throw new Error("error");
});
test.then(
(res) => {
console.log(res); // 无输出
},
(rej) => {
console.log(rej);
}
);
因为setTimeout
方法执行将resolve
函数导致then
方法比resolve
先执行,所以当时Promise状态为pending
,在then
中还没有处理pending
的情况,导致无输出。
处理执行函数时如果抛出错误 这时Promise
的状态因由pending
转为rejected
,而捕获异常需要用到try catch
constructor(exec) {
this.status = PROMISE_PENDING_STATE;
this.result = null;
this.reason = null;
this.resolveCallbacks = [];
this.rejectCallbacks = [];
try {
exec(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(result) {
if (this.status === PENDING) {
this.status = FULFILLED;
this.result = result;
this.resolveCallbacks.forEach((fn) => {
fn(result);
});
}
}
reject(reason) {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectCallbacks.forEach((fn) => {
fn(reason);
});
}
}
then(onFULFILLED, onREJECTED) {
if (this.status === PENDING) {
this.resolveCallbacks.push(onFULFILLED);
this.rejectCallbacks.push(onREJECTED);
}
if (this.status === FULFILLED) {
onFULFILLED(this.result);
}
if (this.status === REJECTED) {
onREJECTED(this.reason);
}
}
}
const test = new selfPromise((resolve, reject) => {
setTimeout(() => {
resolve("siu is good");
});
// throw new Error("error");
});
test.then(
(res) => {
console.log(res); // siu is good
},
(rej) => {
console.log(rej); //reject is good
}
);
继续优化then功能
- 处理
then
函数参数
then(onFULFILLED, onREJECTED) {
// Promise 中的 then 方法回调参数都是可选的,当调用 then 方法未传参数时,需要给默认值
onFULFILLED =
typeof onFULFILLED === "function"
? onFULFILLED
// 值穿透
: (value) => {
return value;
};
onREJECTED =
typeof onREJECTED === "function"
? onREJECTED
: (reason) => {
throw reason;
};
...
}
- 在
Promise
中then
方法是异步执行的。让then
方法在同步任务完成后执行,通过setTimeout
方法将then
方法的执行延后,在同步任务执行完毕后then
方法才会被调用。
resolve(result) {
setTimeout(() => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.result = result;
this.resolveCallbacks.forEach((fn) => {
fn(result);
});
}
});
}
reject(reason) {
setTimeout(() => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectCallbacks.forEach((fn) => {
fn(reason);
});
}
});
}
then(onFULFILLED, onREJECTED) {
if (this.status === PENDING) {
this.resolveCallbacks.push(onFULFILLED);
this.rejectCallbacks.push(onREJECTED);
}
if (this.status === FULFILLED) {
setTimeout(() => {
onFULFILLED(this.result);
});
}
if (this.status === REJECTED) {
setTimeout(() => {
onREJECTED(this.reason);
});
}
}
}
console.log("1");
const test = new selfPromise((resolve, reject) => {
resolve("siu is good");
});
test.then(
(res) => {
console.log("3 " + res);
},
(rej) => {}k
);
console.log("2");
//输出
//1
//2
//3 siu is good
- 链式调用
then
方法的链式调用 要实现链式调用需要让then
方法有返回值并且是Promise
对象 下一个then
方法会依赖上一个then
方法的回调函数返回值
then(onFULFILLED, onREJECTED) {
...
//重复逻辑太多抽离成函数
const fn = (fn) => {
try {
const result = fn(this.result);
if (result instanceof selfPromise) {
result.then(
(res) => {
resolve(res);
// console.log(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
};
if (this.status === FULFILLED) {
setTimeout(() => {
// try {
// const result = onFULFILLED(this.result);
// resolvePromise(newPromise, result, resolve, reject);
// } catch (error) {
// reject(error);
// }
fn(onFULFILLED);
});
}
if (this.status === REJECTED) {
setTimeout(() => {
// try {
// const reason = onREJECTED(this.result);
// resolvePromise(newPromise, reason, resolve, reject);
// } catch (error) {
// reject(error);
// }
fn(onREJECTED);
});
}
if (this.status === PENDING) {
this.resolveCallbacks.push(() => {
// try {
// const result = onFULFILLED(this.result);
// resolvePromise(newPromise, result, resolve, reject);
// } catch (error) {
// reject(error);
// }
fn(onFULFILLED);
});
this.rejectCallbacks.push(() => {
// try {
// const result = onREJECTED(this.result);
// resolvePromise(newPromise, result, resolve, reject);
// } catch (error) {
// reject(error);
// }
fn(onREJECTED);
});
}
});
return newPromise;
}
const test = new selfPromise((resolve, reject) => {
resolve("siu is good");
});
test
.then((res) => {
console.log("1 " + res);
return new selfPromise((resolve, reject) => {
resolve(res);
});
})
.then((res) => {
console.log(res);
});
// 1 siu is good
// siu is good
Promise 实例对象方法的实现
catch
catch(onRejected)
:该方法是 then()
方法的一个特殊形式,用于注册对 Promise
拒绝状态的处理函数。它只接收一个参数 onRejected
,表示在 Promise
拒绝时要执行的回调函数。catch()
方法也返回一个新的 Promise
对象,可以用于链式调用。
catch(onREJECTED) {
return this.then(null, onREJECTED);
}
const test = new selfPromise((resolve, reject) => {
reject("siu siu siu");
});
test.then().catch((rea) => {
console.log(rea);
});
// siu siu siu
finally
finally(onFinally)
:该方法在 Promise
的状态最终确定后执行指定的回调函数,无论是解决还是拒绝状态。它接收一个参数 onFinally
,表示要执行的回调函数。finally()
方法返回一个新的 Promise
对象,可以用于链式调用。
finally特点
- finally 没有参数
- 成功和失败都会走的回调
- 成功的返回值
- 错误是能捕获到的
finally(onFinally) {
// `then(() => value)` 表示 `onFinally` 执行完毕后,仍然返回原 Promise 的成功值 `value`。
return this.then(
(value) => selfPromise.resolve(onFinally()).then(() => value),
(reason) =>
selfPromise.resolve(onFinally()).then(() => {
throw reason;
})
);
}
const test = new selfPromise((resolve, reject) => {
reject("siu siu siu");
//resolve("666");
});
test
.then()
.catch((rea) => {
console.log(rea);
})
.finally(() => {
console.log("123");
});
//siu siu siu
//123
Promise 静态方法的实现
all
⭐⭐⭐ all
:该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise
对象。这个新的 Promise
对象在所有传入的 Promise
都解决时才会解决,并把所有解决结果按顺序作为数组传递给回调函数。如果传入的 Promise
中有任何一个被拒绝,它将立即拒绝并把第一个拒绝原因传递给回调函数
static all(promises) {
let result = [];
let resolveCount = 0;
return new selfPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(res) => {
// 记录数据
result[i] = res;
resolveCount++;
if (resolveCount === promises.length) {
resolve(result);
}
},
(reason) => {
reject(reason);
}
);
}
});
}
const t1 = Promise.resolve("1");
const t2 = Promise.resolve("2");
const t3 = Promise.resolve("3");
const t = selfPromise.all([t1, t2, t3]).then((res) => {
console.log(res);
});
any
any:Promise.any(iterable)
该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise
对象。这个新的 Promise
对象在传入的任意一个 Promise
解决时立即解决,并将该解决值传递给回调函数。如果传入的所有 Promise
都被拒绝,它将立即拒绝并把所有拒绝原因作为数组传递给回调函数。
static any(promises) {
return new selfPromise((resolve, reject) => {
const errors = [];
let completedCount = 0;
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(res) => {
resolve(res);
},
(err) => {
errors.push({ index: i, err});
completedCount++;
if (completedCount === promises.length) {
reject(new AggregateError(errors));
}
}
);
}
});
}
race
race(iterable)
:该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise
对象。这个新的 Promise
对象在传入的任意一个 Promise
解决或拒绝时立即解决或拒绝,并把第一个解决或拒绝的结果传递给回调函数。
static race(promises) {
return new selfPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(res) => {
resolve(res);
},
(reason) => {
reject(reason);
}
);
}
});
}
const t1 = Promise.resolve("1");
const t2 = Promise.resolve("2");
const t3 = Promise.resolve("3");
const t4 = Promise.reject("4");
selfPromise.race([t2, t1, t3, t4]).then((res) => {
console.log(res);
});
// 2
Promise.allSettled
allSettled:
该方法接收一个可迭代对象(比如数组)作为参数,返回一个新的 Promise
对象。这个新的 Promise
对象在传入的所有 Promise
都已解决或拒绝时才会解决,并把所有 Promise
的最终结果作为对象数组传递给回调函数。每个对象包含一个 status
属性,表示 Promise
的状态(“fulfilled” 表示解决,“rejected” 表示拒绝),以及一个 value
或 reason
属性,分别表示解决值或拒绝原因。
static allSettled(promises) {
return new selfPromise((resolve) => {
const results = [];
let pendingCount = promises.length;
for (let i = 0; i < promises.length; i++) {
promises[i]
.then(
(value) => {
results[i] = { status: "fulfilled", value };
},
(reason) => {
results[i] = { status: "rejected", reason };
}
)
.finally(() => {
pendingCount--;
if (pendingCount === 0) {
resolve(results);
}
});
}
});
}
const t1 = Promise.resolve("1");
const t2 = Promise.resolve("2");
const t3 = Promise.resolve("3");
const t4 = Promise.reject("4");
selfPromise.allSettled([t1, t2, t3, t4]).then((res) => {
console.log(res);
});
// [
// { status: 'fulfilled', value: '1' },
// { status: 'fulfilled', value: '2' },
// { status: 'fulfilled', value: '3' },
// { status: 'rejected', reason: '4' }
// ]
Promise.defer
它的目的是提供一个接口,让你可以创建一个 Promise 并直接访问其 resolve
和 reject
方法。不过Promise.defer是一个非标准的用法。被现代 Promise
构造函数替代
Promise.defer = function(){
let resolve, reject;
// 创建一个新的 Promise
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
// 返回包含 promise、resolve 和 reject 的对象
return { promise, resolve, reject };
}
function setDelay(test){
// return new Promise((res,rej) => {
let {promise,resolve,reject} =Promise.defer()
setTimeout(() => {
resolve(test)
})
// })
return promise
}
最后的完整代码
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class selfPromise {
constructor(exec) {
this.status = PENDING;
this.result = null;
this.resolveCallbacks = [];
this.rejectCallbacks = [];
exec(this.resolve.bind(this), this.reject.bind(this));
}
resolve(result) {
setTimeout(() => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.result = result;
this.resolveCallbacks.forEach((fn) => {
fn(result);
});
}
});
}
reject(result) {
setTimeout(() => {
if (this.status === PENDING) {
this.status = REJECTED;
this.result = result;
this.rejectCallbacks.forEach((fn) => {
fn(result);
});
}
});
}
then(onFULFILLED, onREJECTED) {
// Promise 中的 then 方法回调参数都是可选的,当调用 then 方法未传参数时,需要给默认值
onFULFILLED =
typeof onFULFILLED === "function"
? onFULFILLED
: (value) => {
return value;
};
onREJECTED =
typeof onREJECTED === "function"
? onREJECTED
: (reason) => {
throw reason;
};
const newPromise = new selfPromise((resolve, reject) => {
const fn = (fn) => {
try {
const result = fn(this.result);
if (result instanceof selfPromise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
} catch (err) {
reject(err);
}
};
if (this.status === FULFILLED) {
setTimeout(() => {
fn(onFULFILLED);
});
}
if (this.status === REJECTED) {
setTimeout(() => {
fn(onREJECTED);
});
}
if (this.status === PENDING) {
this.resolveCallbacks.push(() => {
fn(onFULFILLED);
});
this.rejectCallbacks.push(() => {
fn(onREJECTED);
});
}
});
return newPromise;
}
catch(onREJECTED) {
return this.then(null, onREJECTED);
}
finally(onFinally) {
return this.then(
(value) => selfPromise.resolve(onFinally()).then(() => value),
(reason) =>
selfPromise.resolve(onFinally()).then(() => {
throw reason;
})
);
}
static resolve(result) {
return new selfPromise((resolve, reject) => {
if (result instanceof selfPromise) {
result.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
} else {
resolve(result);
}
});
}
static reject(result) {
return new selfPromise((resolve, reject) => {
reject(result);
});
}
static all(promises) {
let result = [];
let resolveCount = 0;
return new selfPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(res) => {
// 记录数据
result[i] = res;
resolveCount++;
if (resolveCount === promises.length) {
resolve(result);
}
},
(reason) => {
reject(reason);
}
);
}
});
}
static any(promises) {
return new selfPromise((resolve, reject) => {
const errors = [];
let completedCount = 0;
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(res) => {
resolve(res);
},
(err) => {
errors.push({ index: i, err });
completedCount++;
if (completedCount === promises.length) {
reject(new AggregateError(errors));
}
}
);
}
});
}
static race(promises) {
return new selfPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(
(res) => {
resolve(res);
},
(reason) => {
reject(reason);
}
);
}
});
}
static allSettled(promises) {
return new selfPromise((resolve) => {
const results = [];
let pendingCount = promises.length;
for (let i = 0; i < promises.length; i++) {
promises[i]
.then(
(value) => {
results[i] = { status: FULFILLED, value };
},
(reason) => {
results[i] = { status: REJECTED, reason };
}
)
.finally(() => {
pendingCount--;
if (pendingCount === 0) {
resolve(results);
}
});
}
});
}
}
Promise补充内容
Promise超时相关实现
使用 Promise.race
来实现一个带超时功能的 fetchData
函数。fetchData
函数会在 5 秒钟后解析,而 withTimeout
函数会在给定的超时时间内,如果 fetchData
函数还没有完成,则会拒绝。
function fetchData(){
return new Promise((resolve,reject) => {
setTimeout(() => {
// console.log('1')
resolve('数据以获取')
},5000)
})
}
function withTimeout(promise,ms){
const timeoutPromise = new Promise((res,rej) => {
const timeout = setTimeout(() => {
clearTimeout(timeout)
// console.log('超时')
rej(new Error('超时'))
}, ms);
})
return Promise.race([promise,timeoutPromise])
}
withTimeout(fetchData(),2000).then(() => {
console.log('123')
}).catch((err) => {
console.log(err + '123')
})
中断promise的链式调用
代码中返回了一个永远不会完成的 Promise,因为它既没有调用 resolve
也没有调用 reject
。这种情况会使得链式调用挂起,后续的 then
和 catch
处理都不会被执行。Promise 链会被“中断”,因为 stopChain
返回的 Promise 永远不会完成。
function stopChain(){
return new Promise((resolve,reject)=>{})
}
Promise.resolve().then(() => {
console.log(1)
return stopChain()
}).then(() => {
console.log(2)
}).catch((err) => {
console.log(err)
})
Promise超时重连
fetchWithRetry
函数是一个用于执行带有重试机制的网络请求的工具。这个函数接受两个参数:url
和 retries
。其中,url
是要请求的资源的地址,retries
是允许的最大重试次数,默认值为 3 次。该函数返回一个 Promise 对象,用于处理异步操作。
function fetchWithRetry(url,retries=3){
return new Promise((resolve,reject) => {
function attemptFetch(count) {
fetch(url).then((res) => {
console.log(res)
if(!res.ok){
throw new Error("网络错误")
}
return resolve(res.json())
}).catch((error) => {
console.log(1)
if(count <= retries){
console.log()
setTimeout(() => {
console.log(`正在尝试重连... 第${count}/${retries}次 `)
return attemptFetch(count + 1)
}, 1000);
}else{
reject(error)
}
})
}
attemptFetch(1)
})
}
//实验直接把url搞错就行
const url = "https://jsonplaceholder.typicode.com/posts"
fetchWithRetry(url).then((res) => {
console.log(res)
}
)
串行和并行
串行: 异步任务顺序执行,适合任务有严格顺序要求的情况。
并行: 异步任务同时执行,适合任务独立且可同时进行的情况。时间由最长时间的
//串行
task1().then(() => task2()).then(() => task3());
//并行
Promise.all([task1(), task2(), task3()]).then(() => { });
总结
代码可优化的东西很多,更多作为自我学习,也希望对你有所帮助。
标签:resolve,const,res,必备,源码,Promise,result,reject From: https://blog.csdn.net/weixin_63625059/article/details/142030330