实现一个Promise.race(可以使用Promise)
Promise.race的用法
阮一峰老师的教程:ECMAScript 6 入门 - Promise-race
Promise.race使用示例代码:
const p1 = new Promise((resolve, reject) => {
console.log("p1 new"); // 1.
setTimeout(() => {
console.log("p1 setTimeout 300"); // 6.
resolve("p1");
// reject("p1 err");
}, 300);
});
p1.name = "p1";
console.log("after p1"); // 2.
const p2 = new Promise((resolve, reject) => {
console.log("p2 new"); // 3.
setTimeout(() => {
console.log("p2 setTimeout 200"); // 5.
resolve("p2");
// reject("p2 err");
}, 200);
});
p2.name = "p2";
console.log("after p2"); // 4.
Promise.race([p1, p2])
.then((data) => {
// 先resolve完成的,会进入这里
console.log(data); // p2
})
.catch((err) => {
// 先reject的,会进入这里
console.error(err);
});
Promise的状态
new Promise后如果没有执行resolve或者reject改变它的状态,那么它是pending状态
给Promise实例添加个name属性作为标识
// p0是一个Promise实例
const p0 = new Promise((resolve, reject) => {
console.log("p0 new");
});
p0.name = "p0";
console.log(typeof p0); // object
console.log(Object.prototype.toString.call(p0)); // '[object Promise]'
console.log(p0);
// 打印p0 因为没有执行resolve或者reject改变它的状态,那么它是pending状态
// Promise {<pending>, name: 'p0'}
使用Promise实现Promise.race
参考资料:【手写 Promise 源码】第十二篇 - Promise.race 的实现
Promise.race 是Promise的静态方法,参数为数组,返回一个Promise实例。
在myRace函数中返回一个新的Promise实例pInstance,在new Promise的参数函数中循环promises数组,执行p.then(resolve, reject);,将当前pInstance的resolve, reject函数作为参数传过去。
p1 p2里哪个里面的异步先执行,对应传入的pInstance的resolve(成功状态)或reject(失败状态)函数就会执行。这两个函数作为参数传入了p1和p2的then方法,但最后只会执行一次。resolve的执行时机是取决于p中resolve的时机的,也就实现了race的功能。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1");
// reject("p1 err");
}, 300);
});
p1.name = "p1";
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2");
// reject("p2 err");
}, 200);
});
p2.name = "p2";
// promises 数组中有多个promise实例
Promise.myRace = function (promises) {
const pInstance = new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
console.log(p); // 是按照promises传入顺序打印的
// p1和p2都执行then方法,并将当前pInstance的resolve, reject函数作为参数传过去
// then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数
// p1 p2里哪个里面的异步先执行,对应传入的pInstance的resolve(成功状态)或reject(失败状态)函数就会执行
// 这个两个函数虽然作为参数传入了p1和p2的then方法,但最后只会执行一次
// resolve的执行时机是取决于p中resolve的时机的
// 也就实现了race的功能
p.then(resolve, reject);
}
});
return pInstance;
};
// 调用 Promise.myRace 返回了一个新的 Promise
const newPromise = Promise.myRace([p1, p2]);
newPromise
.then((data) => {
// 先resolve完成的,会进入这里
console.log("newPromise data:", data);
})
.catch((err) => {
// 先reject的,会进入这里
console.error(err);
});
/*
// p2先执行了,简化示意代码如下:
const pInstance = new Promise((resolve, reject) => {
// p2中的异步执行后,resolve("p2") 执行,然后会进入这里的resolve
// 将数据作为参数给这里的resolve
p2.then(resolve, reject);
});
// 最终数据会被then的第一个函数参数接收到
pInstance.then((data) => {
console.log(data);
});
*/
优化Promise.myRace
增加对于判断传入的数组项的判断,如果不是Promise实例,直接执行resolve,并将该项作为resolve函数的参数。与Promise.race的行为一致。
Promise.myRace1 = function (promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
// 增加判断p必须是Promise实例
if (Object.prototype.toString.call(p) === "[object Promise]") {
p.then(resolve, reject);
} else {
// 否则直接resolve传入的参数
resolve(p);
}
}
});
};
Promise.myRace1([p1, p2, "1"])
.then((data) => {
// 先resolve完成的,会进入这里
// 直接打印字符串 '1'
console.log("newPromise data:", data);
})
.catch((err) => {
// 先reject的,会进入这里
console.error(err);
});