Promise
pending(初始状态)、fulfilled(成功状态)和 rejected(失败状态)
Promise 状态 三个状态:pending、fulfilled、reject 两个过程:padding -> fulfilled、padding -> rejected Promise 什么时候会进入 catch 当 pending 为 rejected 时,会进入 catch
实现步骤如下:
- 创建 Promise 实例:使用
new Promise关键字创建一个新的 Promise 实例,并立即执行一个执行器函数(executor function)。 - 执行器函数:执行器函数接收两个参数:
resolve和reject。这两个函数用于改变 Promise 的状态。 - 状态改变:
- 如果执行器函数内的异步操作成功,调用
resolve函数,将 Promise 的状态改为fulfilled,并传递一个值给.then()方法的回调函数。 - 如果执行器函数内的异步操作失败,调用
reject函数,将 Promise 的状态改为rejected,并传递一个错误对象给.catch()方法的回调函数。
- 如果执行器函数内的异步操作成功,调用
- 回调函数注册:
.then()方法用于注册成功的回调函数,.catch()方法用于注册失败的回调函数。 - 链式调用:
.then()和.catch()方法可以返回一个新的 Promise 对象,允许链式调用。
手写 promise
Promise.js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class CustomPromise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => callback());
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback());
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
onRejected = typeof onRejected === 'function' ? onRejected : (reason) => {
throw reason;
};
const newPromise = new CustomPromise((resolve, reject) => {
const handleFulfilled = () => {
try {
const result = onFulfilled(this.value);
resolvePromise(newPromise, result, resolve, reject);
} catch (error) {
reject(error);
}
};
const handleRejected = () => {
try {
const result = onRejected(this.reason);
resolvePromise(newPromise, result, resolve, reject);
} catch (error) {
reject(error);
}
};
if (this.status === FULFILLED) {
setTimeout(handleFulfilled, 0);
} else if (this.status === REJECTED) {
setTimeout(handleRejected, 0);
} else {
this.onFulfilledCallbacks.push(() => setTimeout(handleFulfilled, 0));
this.onRejectedCallbacks.push(() => setTimeout(handleRejected, 0));
}
});
return newPromise;
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(callback) {
return this.then(
(value) => CustomPromise.resolve(callback()).then(() => value),
(reason) => CustomPromise.resolve(callback()).then(() => {
throw reason;
})
);
}
static resolve(value) {
if (value instanceof CustomPromise) {
return value;
}
return new CustomPromise((resolve) => resolve(value));
}
static reject(reason) {
return new CustomPromise((_, reject) => reject(reason));
}
static all(promises) {
return new CustomPromise((resolve, reject) => {
const results = [];
let completedCount = 0;
if (promises.length === 0) {
resolve(results);
return;
}
const processPromise = (index, promise) => {
CustomPromise.resolve(promise).then(
(value) => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
},
(reason) => {
reject(reason);
}
);
};
for (let i = 0; i < promises.length; i++) {
processPromise(i, promises[i]);
}
});
}
static race(promises) {
return new CustomPromise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
CustomPromise.resolve(promises[i]).then(
(value) => {
resolve(value);
},
(reason) => {
reject(reason);
}
);
}
});
}
}
function resolvePromise(promise, result, resolve, reject) {
if (promise === result) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
if (result instanceof CustomPromise) {
result.then(
(value) => resolvePromise(promise, value, resolve, reject),
(reason) => reject(reason)
);
} else if (result !== null && (typeof result === 'object' || typeof result === 'function')) {
let then;
try {
then = result.then;
} catch (error) {
return reject(error);
}
if (typeof then === 'function') {
let called = false;
try {
then.call(
result,
(value) => {
if (called) return;
called = true;
resolvePromise(promise, value, resolve, reject);
},
(reason) => {
if (called) return;
called = true;
reject(reason);
}
);
} catch (error) {
if (called) return;
reject(error);
}
} else {
resolve(result);
}
} else {
resolve(result);
}
}
- 构造函数:初始化
Promise的状态为pending,并定义resolve和reject方法来改变状态。执行executor函数时,若出现异常则调用reject。 then方法:返回一个新的Promise,根据当前Promise的状态处理onFulfilled和onRejected回调,并使用resolvePromise处理结果。catch方法:调用then方法,只传入onRejected回调。finally方法:无论Promise状态如何,都会执行callback,并返回一个新的Promise。resolve静态方法:如果传入的是CustomPromise实例则直接返回,否则创建一个已解决的Promise。reject静态方法:创建一个已拒绝的Promise。all静态方法:接收一个Promise数组,当所有Promise都成功时,返回包含所有结果的数组;若有一个失败,则立即拒绝。race静态方法:接收一个Promise数组,哪个Promise率先改变状态,就以该状态和结果解决返回的Promise。resolvePromise函数:处理then方法返回值的解析逻辑,避免循环引用等问题。
使用
// 测试自定义 Promise
const promise1 = new CustomPromise((resolve) => {
setTimeout(() => {
resolve('Promise 1 resolved');
}, 1000);
});
const promise2 = new CustomPromise((resolve) => {
setTimeout(() => {
resolve('Promise 2 resolved');
}, 2000);
});
CustomPromise.all([promise1, promise2]).then((results) => {
console.log(results);
}).catch((error) => {
console.error(error);
});
手写 promise.race
Promise.race 是 JavaScript 中 Promise 对象的一个静态方法,它接收一个可迭代对象(通常是数组)作为参数,该数组中的每个元素都是一个 Promise 实例。Promise.race 会返回一个新的 Promise,这个新 Promise 会在传入的 Promise 数组中任意一个 Promise 率先改变状态(成功或失败)时,以相同的状态和结果进行解决。
PromiseRace.js
function customPromiseRace(promises) {
return new Promise((resolve, reject) => {
// 遍历传入的可迭代对象中的每个 Promise
for (let i = 0; i < promises.length; i++) {
// 使用 Promise.resolve 将元素转换为 Promise 对象
Promise.resolve(promises[i])
.then((value) => {
// 若有 Promise 成功,立即将结果传递给新 Promise 的 resolve 函数
resolve(value);
})
.catch((error) => {
// 若有 Promise 失败,立即将错误传递给新 Promise 的 reject 函数
reject(error);
});
}
});
}
- 返回新
Promise:customPromiseRace函数返回一个新的Promise实例,这个实例会根据传入数组中率先完成的Promise来改变自身状态。 - 遍历
Promise数组:使用for循环遍历传入的promises数组。 - 处理每个
Promise:对数组中的每个元素使用Promise.resolve进行包装,确保它是一个Promise对象。然后为其添加then和catch方法。- 如果某个
Promise成功(状态变为fulfilled),就调用resolve函数,将结果传递给新Promise实例,使其状态变为fulfilled。 - 如果某个
Promise失败(状态变为rejected),就调用reject函数,将错误传递给新Promise实例,使其状态变为rejected。
- 如果某个
使用
const promise1 = new Promise((resolve) => setTimeout(() => resolve('Promise 1 完成'), 1000));
const promise2 = new Promise((resolve) => setTimeout(() => resolve('Promise 2 完成'), 500));
customPromiseRace([promise1, promise2]).then((result) => {
console.log(result);
}).catch((error) => {
console.error(error);
});
在这个示例中,promise2 会先完成,所以 customPromiseRace 返回的 Promise 会以 promise2 的结果进行解决,最终控制台会输出 Promise 2 完成。
手写 promise.all
Promise.all 是 JavaScript 中 Promise 对象的一个静态方法,它接收一个可迭代对象(通常是数组)作为参数,数组里每个元素都是一个 Promise 实例。该方法会返回一个新的 Promise,当传入的所有 Promise 都成功(状态变为 fulfilled)时,新 Promise 才会成功,其结果是一个包含所有 Promise 结果的数组;若其中任何一个 Promise 失败(状态变为 rejected),新 Promise 会立即失败,结果为第一个失败 Promise 的错误信息。
PromiseAll.js
function customPromiseAll(promises) {
return new Promise((resolve, reject) => {
// 用于存储每个 Promise 的结果
const results = [];
// 记录已经完成的 Promise 数量
let completedCount = 0;
// 如果传入的数组为空,直接成功返回空数组
if (promises.length === 0) {
resolve(results);
return;
}
// 遍历传入的每个 Promise
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i])
.then((value) => {
// 将当前 Promise 的结果存入对应的位置
results[i] = value;
// 完成数量加 1
completedCount++;
// 当所有 Promise 都完成时,新 Promise 成功
if (completedCount === promises.length) {
resolve(results);
}
})
.catch((error) => {
// 若有任何一个 Promise 失败,新 Promise 立即失败
reject(error);
});
}
});
}
代码解释
- 返回新
Promise:customPromiseAll函数返回一个新的Promise实例,它会根据传入数组中所有Promise的完成情况来改变自身状态。 - 初始化变量:
results数组用于存储每个Promise的结果,其索引和传入数组中Promise的索引对应。completedCount用于记录已经完成的Promise数量。
- 处理空数组情况:若传入的数组为空,直接调用
resolve函数,使新Promise成功,结果为空数组。 - 遍历
Promise数组:使用for循环遍历传入的promises数组。 - 处理每个
Promise:- 使用
Promise.resolve确保每个元素都是Promise对象。 - 为每个
Promise添加then和catch方法。- 若
Promise成功,将结果存入results数组对应位置,completedCount加 1。当completedCount等于数组长度时,说明所有Promise都已成功,调用resolve函数使新Promise成功,结果为results数组。 - 若
Promise失败,调用reject函数使新Promise立即失败,结果为该Promise的错误信息。
- 若
- 使用
使用示例
const promise1 = new Promise((resolve) => setTimeout(() => resolve('Promise 1 完成'), 1000));
const promise2 = new Promise((resolve) => setTimeout(() => resolve('Promise 2 完成'), 2000));
customPromiseAll([promise1, promise2]).then((results) => {
console.log(results);
}).catch((error) => {
console.error(error);
});
在这个示例中,只有当 promise1 和 promise2 都成功完成后,customPromiseAll 返回的 Promise 才会成功,最终控制台会输出 ['Promise 1 完成', 'Promise 2 完成']。