相信大家对Promise都有基本的认识 尤其是在React Vue项目 Promise使用频率还是很高的,Promise的出生是为了解决一个事情-让开发者更合理、更规范地用于处理异步操作
因为js是单线程的设计,js有同步任务和异步任务两个队列,同步:顾名思义,就是按顺序依次执行,异步则是没有顺序的,会根据执行时长去返回任务的结果,常见于开发过程中的ajax请求,当我们使用一个请求的结果作为下个请求得我参数时,回调嵌套就会形成回调地狱:
$ajax({
success(res1){
$ajax({
success(res2){
$ajax({
success(res3){
console.log('回调地狱就形成了')
}
})
}
})
}
})
为了解决以上的类似问题 Promise就出生了 Promise A+规范 ,传统的写法,为了得到res3,我们必须依赖res1和res2,而且有更多层和更多的逻辑运算的时候,代码特别难以维护,也增加了请求时更多的等待时间,ES6为了规范它,所以就有了Promise的出现了。Promise对象能使我们更合理、更规范地进行处理异步操作。
Promise 的基本形式
const prs = new Promise((resolve,reject)=>{
resolve('成功的结果')
reject('失败的结果')
})
Promise的三种状态
1.pending:Promise被刚创建的时候状态为pending,表示初始状态;
2.fulfilled:resolve方法调用的时候,表示操作成功;
3.rejected:reject方法调用的时候,表示操作失败;
状态只能从初始化转换为成功或失败,状态不可逆
.then 和.catch方法
.then为处理成功后的业务逻辑
prs.then(res=>{
//res为成功的返回值 也就是我们通过resolve包裹的结果
})
.catch为处理失败后的业务逻辑
prs.then(res=>{
//res为成功的返回值 也就是我们通过resolve包裹的结果
}).catch(error=>{
//error是失败的结果 我们通过reject包裹的结果
})
Promise.all()方法,接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。
const prs1 = new Promise((resolve,reject)=>{
resolve('prs1成功执行了')
})
const prs2 = new Promise((resolve,reject)=>{
resolve('prs2成功执行了')
})
Promise.all([prs1,prs2]).then(res=>{
此时prs1和prs2都执行成功Promise.all才会返回正确的数组,有一个失败就会导致Promise.all()失败
})
Promise.race()方法,接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都有一个为fulfilled时,Promise.race( )就会返回正确的结果。
const prs1 = new Promise((resolve,reject)=>{
resolve('prs1成功执行了')
})
const prs2 = new Promise((resolve,reject)=>{
reject('prs2执行失败了')
})
Promise.race([prs1,prs2]).then(res=>{
此时prs1执行成功了,prs2执行失败了,但是Promise.race()会返回prs1作为执行成功的结果,因为Promise.race()有一个执行成功就会返回第一个成功对应的结果
})
回顾完Promise的基础知识,下面开始手写Promise
class Promise {
PromiseState = "pending"; //准备状态
PromiseResult = null; //结果
FULFILLED = "fulfilled"; //成功的状态
REJECTED = "rejected"; //成功的状态
fulfilledList = []; //成功回调的管理数组
rejectedList = []; //失败回调的管理数组
constructor(executor) {
this.initBind();
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
initBind() {
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
}
// 成功的执行函数
resolve = (value) => {
this.PromiseState = this.FULFILLED; //改变状态
this.PromiseResult = value; //赋值
};
reject = (reason) => {
this.PromiseState = this.REJECTED; //改变状态
this.PromiseResult = reason; //赋值
};
// then方法可以接受两个回调 分别是成功和失败的回调
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (val) => val;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
// 根据状态执行回调函数
if (this.PromiseState === this.FULFILLED) onFulfilled(this.PromiseResult);
if (this.PromiseState === this.REJECTED) onRejected(this.PromiseResult);
}
}
//基础的then方法就写好了 先测试一下
const prs = new Promise((resolve, reject) => {
resolve("成功");
// reject("失败");
});
prs.then(
(res) => {
console.log(res);
},
(error) => {
console.log(error);
}
);
//控制台分别执行了对应的结果 ok 继续完善then方法
这个时候我们的then方法是同步的 并且我们的结果只判断了状态为FULFILLED和REJECTED,如果在new Promise中执行一个异步时 就无法执行
const prs = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功");
});
// reject("失败");
});
prs.then((res) => {
console.log(res);
});
//此时打印的结果为空
那我们就需要一个执行器的管理数组,等状态改变的时候再去执行数组里面保存的方法
接上文说到 我们执行一个异步的时候 我们现在写的是没有打印结果的 这是因为resolve 和reject延时进入 导致此时的PromiseState的状态为Pedding 所以不会调用Promise中的resolve和reject方法,那我们就继续完善代码,当执行异步的时候应该有一个数组去管理Promise的执行队列,然后再循环执行这个数组里面的方法
fulfilledList = []; //成功回调的管理数组
rejectedList = []; //失败回调的管理数组
//类中新增两个管理数组
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (val) => val;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
// 判断状态
if (this.PromiseState === this.FULFILLED) onFulfilled(this.PromiseResult);
if (this.PromiseState === this.REJECTED) onRejected(this.PromiseResult);
if (this.PromiseState == "pending") {
//此时当PromiseState的状态为pedding时 我们根据调用.then时传去的resolve和reject去根据fulfilledList,rejectedList两个数组分别管理
this.fulfilledList.push((value) => {
setTimeout(() => {
onFulfilled(value);
}, 0);
});
this.rejectedList.push((reason) => {
setTimeout(() => {
onFulfilled(reason);
}, 0);
});
}
}
//在resolve 和 reject再循环执行 两个数组中保存的方法
resolve = (value) => {
this.PromiseState = this.FULFILLED; //改变状态
this.PromiseResult = value; //赋值
this.fulfilledList.forEach((e) => e(value));
};
reject = (reason) => {
this.PromiseState = this.REJECTED; //改变状态
this.PromiseResult = reason; //赋值
this.fulfilledList.forEach((e) => e(reason));
};
//此时在测试一下
const prs = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功");
// reject("失败");
});
});
prs.then((res) => {
console.log(res);
});
正常执行了
下面开始实现Promise的链式调用
先看一下原生的Promise链式调用
new Promise((resolve, reject) => {
resolve("成功");
})
.then(console.log(123))
.then((res) => {
console.log(res);
});
//打印台分别打印 123 和 成功