手写 promise ( 三 ) Promise API 实现
Promise.resolve
Promise.resolve(value) 方法会返回一个新的 Promise 实例,该实例的状态为 fulfilled 。
值有三种情况
- 普通值
thable对象,含有then方法的对象promise如果值是promise将对象返回,如果是普通值将值转化为Promise对象执行resolve方法,如果是thenable对象,将该对象转化为Promise对象,执行then方法。
案例
let p = Promise.resolve(1)
// 等价于 let p = new Promise(res=>{res(1)})
p.then(res=>{
console.log('res',res)
})
// res 1
实现
...
const isPromise = (val) => {
if ((typeof val === "object" && val != null) || typeof val == "function") {
if (typeof val.then == "function") {
return true;
} else {
return false;
}
} else {
return false;
}
};
MyPromise.resolve = (val) => {
if (isPromise(val)) {
return val;
}
return new MyPromise((res, rej) => {
res(val);
});
};
...
Promise.reject
Promise.reject(reason) 方法也会返回一个新的 Promise 实例,该实例的状态为 rejected 。
案例
let p = Promise.reject(1)
// 等价于 let p = new Promise(res=>{res(1)})
p.then(null,err=>{
console.log('err',err)
})
// err 1
实现
...
MyPromise.reject = (reason) => {
return new MyPromise((res, rej) => {
rej(reason);
});
};
...
Promise.all
Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
p 的状态由 p1、p2、p3 决定,分成两种情况。
- 只有
p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。 - 只要
p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
案例
let promise1 = Promise.resolve(1);
let promise2 = Promise.resolve(2);
let promise3 = Promise.reject(3);
let promises = [1, promise2, 3];
Promise.all(promises).then(
(array) => {
console.log("array", array);
},
(err) => {
console.log("err", err);
}
);
// array [ 1, 2, 3 ];
let promises2 = [1, promise2, promise3];
Promise.all(promises2).then(
(array) => {
console.log("array", array);
},
(err) => {
console.log("err", err);
}
);
// err 3
let promises2 = [promise3, promise2, 4];
Promise.all(promises2).then(
(array) => {
console.log("array", array);
},
(err) => {
console.log("err", err);
}
);
// err 3
实现
MyPromise.all = (values) => {
return new MyPromise((resolve, reject) => {
if (Array.isArray(values)) {
let resultArr = [];
let count = 0;
values.forEach((val, idx) => {
Promise.resolve(val)
.then((res) => {
resultArr[idx] = res;
count++;
if (count === values.length) {
resolve(resultArr);
}
})
.catch((err) => {
reject(err);
});
});
} else {
reject(new Error("Array Methods must be provided an Array"));
}
});
};
Promise.catch
cath 方法其实就是 then 方法的语法糖
案例
let p = new Promise((resolve, reject) => {
reject(new Error("错喽 错喽"));
});
p.then((res) => {
console.log("res", res);
}).catch((err) => {
console.log("err", err);
});
// err Error: 错喽 错喽
实现
class MyPromise{
...
// mark then 方法的语法糖
catch(errCallback) {
return this.then(null, errCallback);
}
}
...
Promise.finall
finally 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
finally 后可以链式调用 then 方法,所以返回值是 Promise。
finally 的回调可能是一个异步函数,如果直接调用回调,这里其实异步代码没走完,就拿到上个 Promise 的值,这里用 Promise.resolve 处理。在 Promise 里我们已经写了对于异步函数的处理。
案例
function p1 () {
return new Promise(function (resolve, reject) {
setTimeout(() => {
resolve("p1")
}, 2000);
})
}
function p2 () {
return new Promise(function (resolve, reject) {
reject("失败")
// resolve("p2 成功")
})
}
p2().finally(() => {
console.log("finally");
return p1();
}).then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
实现
class MyPromise{
...
/**
* 无论 Promise 的状态如何都会执行
* @param {Function} callback 回调函数
* @returns {MyPromise}
*/
finally(callback) {
return this.then(
(resolve) => {
// mark 利用 MyPromise 对异步函数的处理机制,处理回调是异步函数的情况
return MyPromise.resolve(callback()).then(() => resolve);
},
(reject) => {
return MyPromise.resolve(callback()).then(() => {
throw reject;
});
}
);
}
}
...
Promise.race
Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3]);
上面代码中,只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。
案例
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p1");
}, 100);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("p2");
}, 200);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("p3");
}, 300);
// }, 30);
});
Promise.race([p1,p2,p3]).then(
(res) => {
console.log("res", res);
},
(err) => {
console.log("err", err);
}
);
实现
...
MyPromise.race = (values) => {
return new MyPromise((resolve, reject) => {
if (Array.isArray(values)) {
values.forEach((val) => {
MyPromise.resolve(val)
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
} else {
reject(new Error("Array Methods must be provided an Array"));
}
});
};
...
Promise.allSettled
有时候,我们希望等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。但是,现有的 Promise 方法很难实现这个要求。
Promise.all 方法只适合所有异步操作都成功的情况,如果有一个操作失败,就无法满足要求。所以又了 Promise.allSettled
Promise.allSettled 方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。等到数组所有 Promise 对象都发生状态变更(不管是 fulfilled 还是 rejected ),返回的 Promise 对象才会发生状态变更且状态总是 fulfilled ,不会变成 rejected。
案例
const p1 = Promise.resolve('p1');
const p2 = new Promise((resolve) => {
setTimeout(() => resolve("p2"), 1000);
});
const p3 = new Promise((resolve) => {
setTimeout(() => resolve("p3"), 3000);
});
const p4 = Promise.reject("err p4");
const p5 = Promise.reject("err p5");
// 1. 所有的Promise都成功了
Promise.allSettled([p1, p2, p3]).then((res) => console.log("res", res));
/**
res [
{ status: 'fulfilled', value: 'p1' },
{ status: 'fulfilled', value: 'p2' },
{ status: 'fulfilled', value: 'p3' }
]
*/
// 2. 有一个Promise失败了
Promise.allSettled([p1, p2, p4]).then((res) =>
console.log(JSON.stringify(res, null, 2))
);
/**
res [
{ status: 'fulfilled', value: 'p1' },
{ status: 'fulfilled', value: 'p2' },
{ status: 'rejected', reason: 'err p4' }
]
*/
// 3. 有两个Promise失败了
Promise.allSettled([p1, p4, p5]).then((res) =>
console.log(JSON.stringify(res, null, 2))
);
/**
res [
{ status: 'fulfilled', value: 'p1' },
{ status: 'rejected', reason: 'err p4' }
{ status: 'rejected', reason: 'err p5' }
]
*/
实现
...
MyPromise.allSettled = (values) => {
return new MyPromise((resolve, reject) => {
if (Array.isArray(values)) {
let resultArr = [];
let count = 0;
values.forEach((val, idx) => {
MyPromise.resolve(val)
.then((res) => {
count++;
resultArr[idx] = {
status: "fulfilled",
value: res,
};
if (count === values.length) {
resolve(resultArr);
}
})
.catch((err) => {
count++;
resultArr[idx] = {
status: "rejected",
reason: err,
};
if (count === values.length) {
resolve(resultArr);
}
});
});
} else {
reject(new Error("Array Methods must be provided an Array"));
}
});
};
...
PS
- 代码仓库地址觉得对你有帮助记得 🌟 Star 哦
- 后续会持续更新相关内容以及其他内容
- 觉得文章不错的话,记得 👍 🌟 嘻嘻
- 如有不足欢迎指正