上篇回顾
promise专题–手写promise01
上篇我们初步完成了基本的promise,但是发现当使用异步调用的时候是行不通的。这篇解决这个问题。
一、优化promise类和then方法
上一篇说道,当resolve或者reject被异步函数包裹的时候,他们没有执行,也就是如下这种情况
/*原因如下:
因为setTimeout是异步函数,所以resolve是最后执行的,先执行同步操作,
也就是说先打印出ok,然后调用then方法,
此时status还是pending的状态,所以不会执行onFulfilled
也就不会打印7777
之后再调用resolve*/
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("7777"); // 此时不会执行
// reject("卧槽,失败了");
})
console.log("ok"); // 第一步执行
});
function Promise(executor) {
let _this = this;
_this.status = "pending"; // 默认状态是等待态
_this.successValue = undefined;
_this.errReason = undefined;
function resolve(value) {
// 只能从等待态变成成功
// 等到执行异步,也就是第三步会执行这里
if (_this.status === "pending") {
_this.status = "fulfilled"; // 状态变成成功
_this.successValue = value;
}
}
function reject(reason) {
if (_this.status === "pending") {
_this.status = "rejected"; // 状态变成失败
_this.errReason = reason;
}
}
executor(resolve, reject);
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let _this = this;
console.log(_this.status); // 此时状态是pending,第二步执行
if (_this.status === "fulfilled") {
onFulfilled(_this.value)
}
if (_this.status === "rejected") {
onRejected(_this.reason)
}
}
解决方法分析:
当then中status为pending的时候说明有异步,此时并没有明确到底该执行resolve还是reject,此时我们将两者的回调全部放入一个各自的数组中存储起来,然后当最后执行resolve或者reject的时候,将数组中存储的函数执行一遍即可.
二、优化后支持异步代码
function Promise(executor) {
let _this = this;
_this.status = "pending"; // 默认状态是等待态
_this.successValue = undefined;
_this.errReason = undefined;
_this.onResolvedCallbacks = [] // 成功时调用的数组
_this.onRejectedCallbacks = [] // 失败时调用的数组
function resolve(value) {
// 只能从等待态变成成功
if (_this.status === "pending") {
_this.status = "fulfilled"; // 状态变成成功
_this.successValue = value;
// 循环数组执行函数
_this.onResolvedCallbacks.forEach(fn=>fn())
}
}
function reject(reason) {
if (_this.status === "pending") {
_this.status = "rejected"; // 状态变成失败
_this.errReason = reason;
_this.onRejectedCallbacks.forEach(fn=>fn())
}
}
executor(resolve, reject);
}
// 定义then方法
Promise.prototype.then = function (onFulfilled, onRejected) {
let _this = this;
// 当resolve再同步代码块中
if (_this.status === "fulfilled") {
onFulfilled(_this.value)
}
// 当reject再同步代码块中
if (_this.status === "rejected") {
onRejected(_this.reason)
}
// 当resolve或者reject异步执行的时候
if (_this.status === "pending") {
// 将成功回调函数放入成功数组中
_this.onResolvedCallbacks.push(function () {
onFulfilled(_this.value)
})
// 将失败回调函数放入失败数组中
_this.onRejectedCallbacks.push(function () {
onRejected(_this.reason)
})
}
}
module.exports = Promise
三、测试
let Promise = require('./promise3')
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("7777");
// reject("卧槽,失败了");
})
console.log("ok");
});
p.then((data) => {
console.log(data); // 成功打印7777
}, (error) => {
console.log(error);
})
四、新的问题
这个时候虽然解决了异步调用的问题,但是此时链式调用会出问题,直接报错,比如
p.then((data) => {
console.log(data);
}, (error) => {
console.log(error);
}).then((data2) => {
console.log(data2);
},(error2) => {
console.log(error2);
})
下一篇优化代码,使其支持链式调用