实现Promise.resolve/reject
这两个方法直接挂载在Promise对象身上,用于快速指定一个带有预定状态的Promise实例,由于它们的实现简单且极其相似,我将它们直接放在这里一起带过。
不过,在实现之前,有一点需要注意的细节,请观察下方的代码,并思考执行结果:
Promise.resolve(Promise.reject(1)).then(
(v) => {
console.log(0);
},
(e) => {
console.log(e);
}
);
Promise.reject(Promise.resolve(1)).then(
(v) => {
console.log(0);
},
(e) => {
console.log(e);
}
);
正确答案是:1
和状态为resolved的Promise实例
,看到了吗,这两个函数的执行逻辑有一些不同:如果resolve
方法的参数是一个Promise实例,那么resolve
方法会根据这个Promise实例的执行结果来改变状态;而reject
方法则会直接将参数作为失败的拒因抛出。
其实很好理解,期待百分百的成功往往不现实,但期待百分百的失败倒是信手拈来。
MyPromise.resolve = function (value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
};
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
实现Promise.all
Promise.all
的实现同样不复杂,但是有一些小细节需要注意。该方法用于执行多个Promise代码,并返回一个新的Promise,这个Promise会根据所有的异步程序执行结束后返回相应的结果来改变状态:
- 如果全部执行成功,则resolve,并按照执行的顺序返回一个终值数组;
- 只要有一个执行失败,则立即reject,并返回当前失败的拒因。
根据要求,我们开始码实现:
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
let successfulPromiseArr = [],
successfulCount = 0; // 用于存在成功完成执行的Promise结果和数量
promises.forEach((promise, index) => {
if (!(promise instanceof MyPromise)) {
successfulPromiseArr[index] = promise;
successfulCount++;
}
promise.then(
(value) => {
successfulPromiseArr[index] = value;
successfulCount++;
if (successfulCount === promises.length) {
resolve(successfulPromiseArr);
}
},
(reason) => {
reject(reason);
}
);
});
});
};
从上面的源码实现中,可以提取出几点关于实现时需要注意的小细节:
- 如果传入的数组中包含非Promise实例对象的数据类型,则直接将其作为终值加入返回数组;
- 因为要按照执行的顺序返回终值,且由于异步代码完成顺序不确定,所以不能使用
push
方法,而是使用脚标的方式进行设置; - 原因同第二点,在判断当前完成的Promise是否为最后一个时不能通过判断数组脚标的方式,上面代码使用了一个变量来进行计数,当完成的数量达到了数组的数量时,再进行resolve。
实现Promise.race
Promise.race
相比Promise.all
来说,逻辑简单了许多,只需要根据第一个完成执行的Promise对象的结果来决定返回状态,同时注意处理传入非Promise实例对象类型数据的情况即可。
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise, index) => {
if (!(promise instanceof MyPromise)) {
resolve(promise);
}
promise.then(
(value) => {
resolve(value);
},
(reason) => {
reject(reason);
}
);
});
});
};
实现Promise.prototype.finally
最后我们再来实现一下这个方法,这个方法实现起来是最简单的一个,它的执行逻辑也非常简单:这个方法无论上一个Promise的返回状态如何,都会执行回调函数中的内容。
MyPromise.prototype.finally = function (callback) {
return this.then(
value => {
callback();
,kreturn value;
},
reason => {
callback();
throw reason;
}
);
};
Promise的缺点
- promise一旦新建,就会立即执行,无法取消
- 如果不设置回掉函数,promise内部抛出的错误就不会反应到外部
- 处于pending状态时,是不能知道目前进展到哪个阶段的