手写 Promise
有问题的代码:
function myPromise(callback) {
// 保存 Promise 的状态和结果
let state = 'pending';
let result = undefined;
// 定义 resolve 函数
function resolve(value) {
// 状态只能从 pending 转变为 fulfilled
if (state === 'pending') {
state = 'fulfilled';
result = value;
}
}
// 定义 reject 函数
function reject(reason) {
// 状态只能从 pending 转变为 rejected
if (state === 'pending') {
state = 'rejected';
result = reason;
}
}
// 执行传入的回调函数
try {
callback(resolve, reject);
} catch (error) {
// 如果回调函数抛出异常,将 Promise 的状态设置为 rejected
reject(error);
}
// 返回一个具有 then 方法的对象
return {
then: function (onFulfilled, onRejected) {
// 根据 Promise 的状态调用相应的回调函数
if (state === 'fulfilled') {
onFulfilled(result);
} else if (state === 'rejected') {
onRejected(result);
}
},
};
}
// 使用手写的 Promise
const promise = myPromise(function (resolve, reject) {
// 模拟异步操作
setTimeout(function () {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber);
} else {
reject('Error: Random number is less than 0.5');
}
}, 10);
});
// 使用 then 方法处理 Promise 的结果
promise.then(
function (value) {
console.log('Fulfilled:', value);
},
function (reason) {
console.log('Rejected:', reason);
}
);
这段代码有什么问题?
这段代码实现了一个简单的 Promise 模拟,但存在一些问题,特别是在处理异步操作和状态管理方面。以下是主要问题及其解决方案:
主要问题
状态管理不完整
当前的 then 方法只在 Promise 状态已经确定后(fulfilled 或 rejected)被调用。如果在调用 then 时,Promise 仍处于 pending 状态,回调函数将不会被执行。这会导致用户无法在 Promise 完成后获取结果。
链式调用支持缺失
当前实现的 then 方法不支持链式调用。每次调用 then 都应该返回一个新的 Promise,以便可以继续调用后续的 then。
异步执行中的状态更新
当 Promise 处于 pending 状态时,应该将传入的回调函数(onFulfilled 和 onRejected)保存起来,并在状态改变时执行它们。
改进后的代码,还是有问题,看不懂
以下是修正过的问题并添加了链式调用支持的代码示例:
完整代码:
function myPromise(callback) {
// 保存 Promise 的状态和结果
let state = 'pending';
let result = undefined;
const onFulfilledCallbacks = [];
const onRejectedCallbacks = [];
// 定义 resolve 函数
function resolve(value) {
if (state === 'pending') {
state = 'fulfilled';
result = value;
// 执行所有 onFulfilled 回调
onFulfilledCallbacks.forEach(cb => cb(result));
}
}
// 定义 reject 函数
function reject(reason) {
if (state === 'pending') {
state = 'rejected';
result = reason;
// 执行所有 onRejected 回调
onRejectedCallbacks.forEach(cb => cb(result));
}
}
// 执行传入的回调函数
try {
callback(resolve, reject);
} catch (error) {
reject(error);
}
// 返回一个具有 then 方法的对象
return {
then: function (onFulfilled, onRejected) {
return myPromise((resolve, reject) => {
// 根据 Promise 的状态调用相应的回调函数
if (state === 'fulfilled') {
onFulfilled ? resolve(onFulfilled(result)) : resolve(result);
} else if (state === 'rejected') {
onRejected ? reject(onRejected(result)) : reject(result);
} else {
// 如果还是 pending 状态,保存回调函数
onFulfilledCallbacks.push(value => {
if (onFulfilled) {
resolve(onFulfilled(value));
} else {
resolve(value);
}
});
onRejectedCallbacks.push(reason => {
if (onRejected) {
reject(onRejected(reason));
} else {
reject(reason);
}
});
}
});
},
};
}
// 使用手写的 Promise
const promise = myPromise(function (resolve, reject) {
setTimeout(function () {
const randomNumber = Math.random();
if (randomNumber > 0.5) {
resolve(randomNumber);
} else {
reject(`Error: Random number ${randomNumber} is less than 0.5`);
}
}, 10);
});
// 使用 then 方法处理 Promise 的结果
promise.then(
function (value) {
console.log('Fulfilled:', value);
return value + 1; // 返回一个新的值以测试链式调用
},
function (reason) {
console.log('Rejected:', reason);
return reason
}
).then(
function (value) {
console.log('Chained Fulfilled:', value);
},
function (reason) {
console.log('Chained Rejected:', reason);
}
);
运行代码
qy@QY [21:36:05] [~/Documents/git_rep/js-logical/2024-09-30-promise-demo1] [main *]
-> % node test6.js
Fulfilled: 0.6364998457900277
Chained Fulfilled: 1.6364998457900277
qy@QY [21:36:06] [~/Documents/git_rep/js-logical/2024-09-30-promise-demo1] [main *]
-> % node test6.js
Rejected: Error: Random number 0.27835075383137275 is less than 0.5
Chained Rejected: Error: Random number 0.27835075383137275 is less than 0.5
改进点总结
状态管理:通过使用数组存储 onFulfilled 和 onRejected 回调函数,在状态改变时执行它们。
链式调用:每次调用 then 返回一个新的 Promise,以支持链式调用。
回调执行:确保在状态改变时能够正确执行相应的回调。
这样修改后的代码更符合 Promise 的规范,能够更好地处理异步操作,并支持链式调用。
参考:
https://www.perplexity.ai/search/function-mypromise-callback-ba-MkWZwC0HR4Cf0zYFHxsfYQ
没有问题的代码,手写一个Promise/A+,完美通过官方872个测试用例
Promise几乎是面试必考点,所以我们不能仅仅会用,还得知道他的底层原理,学习他原理的最好方法就是自己也实现一个Promise。所以本文会自己实现一个遵循Promise/A+规范的Promise。实现之后,我们还要用Promise/A+官方的测试工具来测试下我们的实现是否正确,这个工具总共有872个测试用例,全部通过才算是符合Promise/A+规范,下面是他们的链接:
博客链接:
https://segmentfault.com/a/1190000023157856
本文的完整代码托管在GitHub上: https://github.com/dennis-jiang/Front-End-Knowledges/blob/master/Examples/JavaScript/Promise/MyPromise.js
Promise/A+规范: https://github.com/promises-aplus/promises-spec
Promise/A+测试工具: https://github.com/promises-aplus/promises-tests