promise 手撕
手动实现一个完整的 Promise 是一个复杂的任务,包括 Promise 的状态管理、异步任务调度、回调处理等。以下是一个简化版的 Promise 实现,用于演示 Promise 的基本原理:
promise
js
class MyPromise {
constructor(executor) {
// 初始化 Promise 的状态为 pending
this.state = 'pending';
// 初始化 Promise 的结果值为 undefined
this.value = undefined;
// 存储 then 方法中的回调函数
this.handlers = [];
// 定义 resolve 方法,用于将 Promise 状态从 pending 变为 fulfilled
const resolve = (value) => {
// 确保 Promise 的状态只能从 pending 变为 fulfilled
if (this.state === 'pending') {
this.state = 'fulfilled';
// 存储 resolved 的结果值
this.value = value;
// 执行所有的回调函数
this.callHandlers();
}
};
// 定义 reject 方法,用于将 Promise 状态从 pending 变为 rejected
const reject = (reason) => {
// 确保 Promise 的状态只能从 pending 变为 rejected
if (this.state === 'pending') {
this.state = 'rejected';
// 存储 rejected 的原因
this.value = reason;
// 执行所有的回调函数
this.callHandlers();
}
};
try {
// 执行传入的 executor 函数,并将 resolve 和 reject 作为参数传递进去
executor(resolve, reject);
} catch (error) {
// 如果执行过程中出现异常,直接将 Promise 状态置为 rejected
reject(error);
}
}
// 定义 then 方法,用于添加成功和失败的回调函数
then(onFulfilled, onRejected) {
// 返回一个新的 Promise 对象
return new MyPromise((resolve, reject) => {
// 定义 fulfilledHandler 函数,用于处理 fulfilled 状态的回调
const fulfilledHandler = () => {
if (typeof onFulfilled === 'function') {
try {
// 执行 onFulfilled 回调,并将 resolved 的结果传递给它
const result = onFulfilled(this.value);
// 将 onFulfilled 回调的结果传递给新的 Promise,从而实现链式调用
resolve(result);
} catch (error) {
// 如果 onFulfilled 回调执行过程中出现异常,将新的 Promise 置为 rejected
reject(error);
}
} else {
// 如果 onFulfilled 不是函数,直接将 resolved 的结果传递给新的 Promise
resolve(this.value);
}
};
// 定义 rejectedHandler 函数,用于处理 rejected 状态的回调
const rejectedHandler = () => {
if (typeof onRejected === 'function') {
try {
// 执行 onRejected 回调,并将 rejected 的原因传递给它
const result = onRejected(this.value);
// 将 onRejected 回调的结果传递给新的 Promise,从而实现链式调用
resolve(result);
} catch (error) {
// 如果 onRejected 回调执行过程中出现异常,将新的 Promise 置为 rejected
reject(error);
}
} else {
// 如果 onRejected 不是函数,直接将 rejected 的原因传递给新的 Promise
reject(this.value);
}
};
// 如果 Promise 的状态还是 pending,说明回调函数需要等待,将回调函数存储起来
if (this.state === 'pending') {
this.handlers.push({ fulfilledHandler, rejectedHandler });
} else if (this.state === 'fulfilled') {
// 如果 Promise 已经是 fulfilled 状态,立即执行 fulfilledHandler 回调
fulfilledHandler();
} else if (this.state === 'rejected') {
// 如果 Promise 已经是 rejected 状态,立即执行 rejectedHandler 回调
rejectedHandler();
}
});
}
// 定义 catch 方法,用于添加失败的回调函数,实际上就是 then 方法的语法糖
catch(onRejected) {
return this.then(null, onRejected);
}
// 执行所有的回调函数,保证 then 方法注册的回调能被调用
callHandlers() {
this.handlers.forEach(({ fulfilledHandler, rejectedHandler }) => {
if (this.state === 'fulfilled') {
// 如果 Promise 的状态是 fulfilled,执行 fulfilledHandler 回调
fulfilledHandler();
} else if (this.state === 'rejected') {
// 如果 Promise 的状态是 rejected,执行 rejectedHandler 回调
rejectedHandler();
}
});
}
// 定义静态方法 resolve,返回一个 fulfilled 的 Promise 对象
static resolve(value) {
return new MyPromise((resolve) => {
resolve(value);
});
}
// 定义静态方法 reject,返回一个 rejected 的 Promise 对象
static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}
// 定义静态方法 all,接收一个 Promise 数组作为参数,返回一个新的 Promise 对象
static all(promises) {
// 定义静态方法 all,接收一个 Promise 数组作为参数,返回一个新的 Promise 对象
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let resolvedCount = 0;
promises.forEach((promise, index) => {
// 将每个 Promise 转换为 MyPromise,确保所有 Promise 都被处理
MyPromise.resolve(promise).then(
value => {
// 存储 resolved 的结果值
results[index] = value;
resolvedCount++;
// 当所有 Promise 都被 resolved 时,将新的 Promise 置为 fulfilled,并传递结果数组
if (resolvedCount === promises.length) {
resolve(results);
}
},
// 当有任何一个 Promise 被 rejected 时,将新的 Promise 置为 rejected,并传递原因
reject
);
});
});
}
// 定义静态方法 race,接收一个 Promise 数组作为参数,返回一个新的 Promise 对象
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
// 将每个 Promise 转换为 MyPromise,确保所有 Promise 都被处理
MyPromise.resolve(promise).then(
// 当有任何一个 Promise 被 resolved 时,将新的 Promise 置为 fulfilled,并传递结果
resolve,
// 当有任何一个 Promise 被 rejected 时,将新的 Promise 置为 rejected,并传递原因
reject
);
});
});
}
}
// 测试代码
const promise1 = new MyPromise(resolve => setTimeout(() => resolve(1), 1000));
const promise2 = new MyPromise(resolve => setTimeout(() => resolve(2), 500));
const promise3 = new MyPromise((resolve, reject) => setTimeout(() => reject('error'), 800));
MyPromise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // 输出:[1, 2, "error"]
})
.catch(error => {
console.error(error);
});
MyPromise.race([promise1, promise2, promise3])
.then(result => {
console.log(result); // 输出:2
})
.catch(error => {
console.error(error);
});
Promise.allSettled
是一个 ECMAScript 2020 中引入的新方法,它返回一个在所有给定的 Promise 都已经 fulfilled 或 rejected 后的 Promise,并带有一个对象数组,每个对象表示对应的 Promise 结果。如果一个 Promise 成功了,你会得到一个对象 { status: 'fulfilled', value: resolvedValue }
,如果一个 Promise 失败了,你会得到一个对象 { status: 'rejected', reason: rejectionReason }
。
Promise.allSettled
js
js
function promiseAllSettled(promises) {
return new Promise(resolve => {
const results = [];
let settledCount = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(value => {
results[index] = { status: 'fulfilled', value };
settledCount++;
if (settledCount === promises.length) {
resolve(results);
}
})
.catch(reason => {
results[index] = { status: 'rejected', reason };
settledCount++;
if (settledCount === promises.length) {
resolve(results);
}
});
});
});
}
//输出
const promises = [
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
];
promiseAllSettled(promises)
.then(results => {
console.log(results);
// 输出:[
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 'error' },
// { status: 'fulfilled', value: 3 }
// ]
});
Promise.any
是 ECMAScript 2021 中引入的新方法,它返回一个在任意给定的 Promise 变为 fulfilled 状态后的 Promise。如果所有 Promise 都处于 rejected 状态,则会返回一个 AggregateError,其中包含所有的 rejection 原因。
Promise.any
js
function promiseAny(promises) {
return new Promise((resolve, reject) => {
let rejectedCount = 0;
const errors = [];
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(resolve)
.catch(reason => {
rejectedCount++;
errors[index] = reason;
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
});
});
});
}
//使用上述实现的 promiseAny 函数,你可以按照以下方式调用:
const promises = [
Promise.reject('Error 1'),
Promise.resolve(2),
Promise.reject('Error 3')
];
promiseAny(promises)
.then(result => {
console.log(result); // 输出:2
})
.catch(error => {
console.error(error); // 输出:AggregateError: All promises were rejected
});
Promise.all
是一个非常常用的 Promise 方法,它接收一个 Promise 数组作为输入,返回一个新的 Promise,该 Promise 在所有输入的 Promise 都变为 fulfilled 状态后才会变为 fulfilled 状态,并返回一个包含所有 Promise 结果的数组。如果输入的 Promise 中有一个被 rejected,则返回的 Promise 会立即变为 rejected,并带有第一个被 rejected 的 Promise 的原因。
Promise.all
js
function promiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let fulfilledCount = 0;
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(value => {
results[index] = value;
fulfilledCount++;
if (fulfilledCount === promises.length) {
resolve(results);
}
})
.catch(reject);
});
});
}
//使用上述实现的 promiseAll 函数,你可以按照以下方式调用:
const promises = [
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
];
promiseAll(promises)
.then(results => {
console.log(results); // 输出:[1, 2, 3]
})
.catch(error => {
console.error(error);
});
Promise.race
是一个 Promise 方法,它接收一个 Promise 数组作为输入,返回一个新的 Promise,该 Promise 在输入的 Promise 数组中有任意一个 Promise 变为 fulfilled 或 rejected 状态后,即会变为相应的状态,并带有该 Promise 的结果或原因。
Promise.race
js
function promiseRace(promises) {
return new Promise((resolve, reject) => {
promises.forEach(promise => {
Promise.resolve(promise)
.then(resolve)
.catch(reject);
});
});
}
//使用上述实现的 promiseRace 函数,你可以按照以下方式调用:
const promises = [
new Promise(resolve => setTimeout(() => resolve(1), 1000)),
new Promise(resolve => setTimeout(() => resolve(2), 500)),
new Promise((resolve, reject) => setTimeout(() => reject('error'), 800))
];
promiseRace(promises)
.then(result => {
console.log(result); // 输出:2
})
.catch(error => {
console.error(error); // 输出:error
});
Promise.any
是 ECMAScript 2021 中引入的新方法,它返回一个在任意给定的 Promise 变为 fulfilled 状态后的 Promise。如果所有 Promise 都处于 rejected 状态,则会返回一个 AggregateError,其中包含所有的 rejection 原因。
Promise.any
js
function promiseAny(promises) {
return new Promise((resolve, reject) => {
let rejectedCount = 0;
const errors = [];
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(resolve)
.catch(reason => {
rejectedCount++;
errors[index] = reason;
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
});
});
});
}
//使用上述实现的 promiseAny 函数,你可以按照以下方式调用:
const promises = [
Promise.reject('Error 1'),
Promise.resolve(2),
Promise.reject('Error 3')
];
promiseAny(promises)
.then(result => {
console.log(result); // 输出:2
})
.catch(error => {
console.error(error); // 输出:AggregateError: All promises were rejected
});
并发实现
js
function concurrentPromises(promises, concurrency) {
return new Promise((resolve, reject) => {
const results = [];
let runningCount = 0;
let index = 0;
// 定义一个递归函数,用于执行下一个 Promise
function runNext() {
// 如果已经执行了所有的 Promise,则返回结果
if (index >= promises.length) {
resolve(results);
return;
}
// 取出当前要执行的 Promise
const promise = promises[index];
// 执行当前 Promise,并更新状态
runningCount++;
index++;
Promise.resolve(promise)
.then(result => {
// 当 Promise 执行成功时,将结果存入 results 数组
results.push(result);
})
.catch(error => {
// 当 Promise 执行失败时,直接返回错误
reject(error);
})
.finally(() => {
// 当前 Promise 执行完毕,继续执行下一个 Promise
runningCount--;
// 如果正在执行的 Promise 数量小于并发数,并且还有未执行的 Promise,则继续执行下一个 Promise
while (runningCount < concurrency && index < promises.length) {
runNext();
}
// 如果正在执行的 Promise 数量为 0,并且所有 Promise 都执行完毕,则返回结果
if (runningCount === 0 && index >= promises.length) {
resolve(results);
}
});
}
// 启动并发执行
for (let i = 0; i < concurrency && i < promises.length; i++) {
runNext();
}
});
}
// 测试代码
const delay = (ms, value) => new Promise(resolve => setTimeout(() => resolve(value), ms));
const promises = [
delay(1000, 1),
delay(2000, 2),
delay(1500, 3),
delay(500, 4),
delay(800, 5),
delay(1200, 6),
];
concurrentPromises(promises, 3)
.then(results => {
console.log(results); // 输出:[1, 2, 3, 4, 5, 6]
})
.catch(error => {
console.error(error);
});
上述代码中的 concurrentPromises
函数接受一个 Promise 数组 promises
和并发数 concurrency
作为参数。它会并发执行最多 concurrency
个 Promise,然后等待其中一个 Promise 完成后再继续执行下一个 Promise,直到所有 Promise 都执行完毕。
请注意,实际的 Promise 并发实现可能更加复杂,需要考虑更多的错误处理和边界情况。此处提供的是一个简单的示例实现,用于演示并发的基本原理。在实际项目中,建议使用成熟的 Promise 并发库,如 Promise.all
和 Promise.allSettled
,来实现并发任务。
总结
Promise的并发性方法常用于处理多个promise的并发执行问题,每个方法应用场景大致总结如下:
- Promise.all:用于接收多个promise兑现的结果,若其中有reject的会被reject
- Promise.allSettled:用于接收多个promise兑现/拒绝的结果
- Promise.any:用于接收多个promise中兑现最快的那个的兑现结果,若全部reject则reject
- Promise.race:用于接收多个promise中兑现/拒绝最快的那个的处理结果