小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
序言
Promise编写代码中很常见,我们不要常若知其然而不知其所以然。
当自己提到了Promise的时候面试官问下去,结果不懂了,就不好~哈哈哈
简介
Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
一个Promise必然处于以下三种状态之一
- 待定(pending):初始状态,即没有兑现,也没有被拒绝。
- 已兑现(fulfilled):意味着操作成功
- 已拒绝(rejected):意味操作失败
当pending转换成fulfilled或者rejected时,状态将不会变化。
解决问题:
- 回调地狱,代码难以维护
- 回调会受到控制反转的影响
实现Promise
语法:
new Promise(executor)
executor:是一个双参函数,参数为resolve和reject,Promise的实现会立即执行executor并且传入两个函数,成功调用resolve,状态变成fulfilled,失败调用reject,状态变为rejected。
设计:
- Promise应该是一个构造函数
- 传入一个参数
function MyPromise(executor) {
//1. 固定this,防止resolve和reject函数中this发生变化,或者直接使用箭头函数
let self = this;
//2. Promise的初始状态为pending
self.state = "pending";
//3. Promise的结果值
self.value = undefined;
//---7. 异步执行时then的注册存放的fulfilled状态数组
self.onFulfilledArr = [];
//---8. 异步执行时then的注册存放的rejected状态数组
self.onRejectedArr = [];
//4. executor第一个参数函数
function resolve(res) {
//4.1 判断状态是否为pending
if (self.state !== "pending") return;
//4.2 状态变成已兑现
self.state = "fulfilled";
//4.3 结果值为传入参数
self.value = res;
//---9. 调用then的数组,待定变成成功
self.onFulfilledArr.forEach(item => item());
}
//5. executor第二个参数函数
function reject(err) {
//5.1 判断状态是否为pending
if (self.state !== "pending") return;
//5.2 状态变成已兑现
self.state = "rejected";
//5.3 结果值为传入参数
self.value = err;
//---10. 调用then的数组,待定变成失败
self.onRejectedArr.forEach(item => item());
}
//6. 执行executor
try {
executor(resolve, reject);
}catch(err) {
reject(err);
}
}
实现Promise.prototype.then
then方法可以让Promise支持链式调用
语法:
p.then(onFulfilled[, onRejected]);
onFulfilled和onRejected都为可选
注意:
- then方法返回一个Promise对象
- 当promise的状态变为成功时调用onfulfilled,其中参数为resolve传入的参数
- 当promise的状态变为失败时调用onfulfilled,其中参数为reject传入的参数
- then方法可以多次调用
- onFulfilled不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数
- onRejected不是函数,则会在内部被替换为一个 "Thrower" 函数。
let test2 = new Promise((resolve, reject) => {
resolve("hehe");
});
console.log(test2.then());
let test2 = new Promise((resolve, reject) => {
reject("hehe");
});
console.log(test2.then());
设计:
MyPromise.prototype.then = function (onFulfilled, onRejected) {
//1. 固定this
let self = this;
//2. 判断onFulfilled是否是函数
if (typeof onFulfilled !== "function") {
onFulfilled = res => res;
}
//3. 判断onRejected是否为函数
if (typeof onRejected !== "function") {
onRejected = err => {
throw err;
};
}
//4. 当进入then的时候promise的状态为fulfilled状态
if (self.state === "fulfilled") {
//4.1 返回新的promise对象
return new MyPromise((resolve, reject) => {
try {
//4.2 执行成功态的函数
let x = onFulfilled(self.value);
//4.3 判断返回结果是否是promise
if(x instanceof MyPromise) {
//4.3.1 返回的Promise函数调用then方法作为结果
x.then(res=>resolve(res), err=>reject(err));
return;
}
//4.3.2 返回值直接进入resolve
resolve(x);
} catch (err) {
//4.4 捕获错误
reject(err);
}
});
}
//5. 当进入then的时候promise的为拒绝状态
if (self.state === "rejected") {
return new MyPromise((resolve, reject) => {
try {
//5.1 执行拒绝态函数
let x = onRejected(self.value);
if(x instanceof MyPromise) {
x.then(res=>resolve(res), err=>reject(err));
return;
}
reject(x);
} catch (err) {
reject(err);
}
});
}
//6. 当进入then的时候promise的为待定状态
if (self.state === "pending") {
return new MyPromise((resolve, reject) => {
//6.1 因为不清楚到底到底执行成功态还是失败态,需要存入两个数组Promise里面的(7,8),待到状态敲定进行执行,
self.onFulfilledArr.push(() => {
try {
let x = onFulfilled(self.value);
resolve(x);
} catch (err) {
reject(err);
}
});
self.onRejectedArr.push(() => {
try {
let x = onRejected(self.value);
reject(x);
} catch (err) {
reject(err);
}
});
});
}
}
实现Promise.prototype.catch
catch方法用于promise组合中的错误处理。
它就是then方法的第二个参数函数
示例:
let temp = new Promise((resolve,reject)=>{
reject("temp");
});
temp.then(val=>console.log(val)).then(()=>console.log("2")).catch(err=>console.log(err));
输出:temp
设计:
MyPromise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected);
}
实现Promise.resolve
示例:在resolve方法里面传入Promise实例,返回它本身
设计:
let temp = new Promise((resolve,reject)=>{
resolve("temp");
});
console.log(Promise.resolve(temp));
在resolve方法里里面传入非Promise实例,返回新Promise值,并且状态为成功态
let temp = 1;
console.log(Promise.resolve(temp));
设计:
MyPromise.resolve = function(res) {
if(res instanceof MyPromise) {
return res;
}
return new MyPromise((resolve,reject)=>resolve(res));
}
实现Promise.reject
返回一个带有拒绝原因的Promise
设计:
MyPromise.reject = function(err) {
return new MyPromise((resolve,reject)=>reject(err));
}
实现Promise.all
返回一个Promise,其中迭代器中一个Promise拒绝就拒绝
有多个Promise组合时,且都是完成状态那么Promise.all返回的Promise异步变为完成,如果其中有一个拒绝,那么返回的Promise直接调用失败Promise的回调函数
语法:
Promise.all(iterable);
iterable:为一个可迭代对象
设计:
MyPromise.all = function(mpArr) {
//所有成功态的存储结果
const res = [];
return new MyPromise((resolve, reject) => {
mpArr.forEach((item, index) => {
MyPromise.resolve(item).then(val=>{
res.push(val);
//所有Promise成功
if(index + 1 == mpArr.length) {
resolve(res);
}
}, err => {
//一个失败即失败
reject(err);
});
});
});
}
实现Promise.race
返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
就是迭代器里面的Promise谁先执行完就执行谁
语法:
Promise.race(iterable);
设计:
MyPromise.race = function(mpArr) {
return new MyPromise((resolve, reject) => {
mpArr.forEach(item=>{
MyPromise.resolve(item).then(val=>{
resolve(val);
}, err => {
reject(err);
});
});
});
}
结语
Promise在我所遇到的笔试题当中较少,不过在面试的时候问得很多很多。知识嘛积累积累,也不嫌多
参考: MDN|Promise