Promise相关方法以及原理,手动实现promise相关功能方法
在前端面试中Promise被问到的概率非常大,在我面试的过程中,懂技术的基本都会问相关问题。对于初学者来说并没有将Promise吃透,因此在面试中很容易被问到,同时能够手动实现一个Promise也是进入大厂的基础条件,以下是我对promise做的一些整理,欢迎各位大佬进行补充!
promise是一个构造函数,可以把他看作一个容器,里面可以存放异步代码,可以通过then方法来对结果进行处理,promise本身是一个同步任务,其then方法是一个异步任务。通过resolve,reject将成功或者失败的结构返回出去,解决了回调地狱的问题。那我们来手动实现一个promise对象
//创建Promise构造函数
function Promise(executor){
//目前还没有状态,需要先定义
this.PromiseState="pending";
this.PromiseResult=null;//定义返回的结果;
// this.callback={}保存then中的回调,多个回调会覆盖掉里面的方法,因此换成数组进行保存;
this.callback=[];
const that=this;//由于resolve,reject中无法拿到this(指向全局),但是需要修改其身上的属性,因此采用浅拷贝进行赋值;
//传入的实参resolve,reject是一个函数,在当前作用域并没有定义,一次需要事先定义
function resolve(value){
//resolve改变promise的状态,且状态只能改变一次
if(that.PromiseState!=="pending"){
return
}//只有为pending时才能修改
that.PromiseState="fulfilled"
//修改结果
that.PromiseResult=value
// if(that.callback.onResolved){
// that.callback.onResolved(value)
// }
setTimeout(()=>{
that.callback.forEach(item=>{
item.onResolved(value)
})
})
}
function reject(value){
if(that.PromiseState!=="pending"){
return
}//只有为pending时才能修改
that.PromiseState="rejected"
that.PromiseResult=value
// if(that.callback.onRejected){
// that.callback.onRejected(value)
// }回调为对象时
//回调为数组时
setTimeout(()=>{
//变为异步
that.callback.forEach(item=>{
item.onRejected(value)
})
})
}
//promise接收一个回调,其内部会同步自动调用,传入实参resolve,reject
// executor(resolve,reject)
try{
//throw抛出异常也会将结果抛到reject中,采用的是try,catch的原理;
executor(resolve,reject)//正常情况走try
}catch(e){
//有异常走catch
//抛出的异常会出现在reject中,因此在此调用reject
reject(e)
}
}
定义then方法、`
//定义then方法
Promise.prototype.then=function(onResolved,onRejected){
let that=this
//如果第一个参数没传
if(typeof onResolved !=="function"){
value=>value
}
//如果没有传递第二个参数
if(typeof onRejected !=="function"){
onRejected=reason=>{
console.log(reason,"reason");
throw reason
}
}
//我们知道then方法的返回值也是一个promise对象,同时该对象的状态也是需要根据结果来修改
return new Promise((resolve,reject)=>{
function public(type){
//由于以下代码重复出现频率较高,只有调用的方法不一样,因此提取为公共代码
//处理throw
try{
//下面这个方法就是调用的then方法中的onResolved,会返回得到一个结果
let result=type(that.PromiseResult)
if(result instanceof Promise){
//如果时promise对象则调用then方法将结果返回出去,同时修改状态
result.then((v)=>{
resolve(v)
},(r)=>{
reject(r)
})
}else{
//不是promise对象直接修改状态
resolve(result)
}
}catch(e){
resolve(e)
}
}
if(this.PromiseState==="fulfilled"){
//变为异步
setTimeout(()=>{
public(onResolved)
})
//判断的得到的状态
}else if(this.PromiseState==="rejected"){
setTimeout(()=>{
public(onRejected)
})
// try{
// console.log(1);
// let result=onRejected(this.PromiseResult)
// if(result instanceof Promise){
// result.then((v)=>{
// resolve(v)
// },r=>{
// reject(r)
// })
// }else{
// reject(result)
// }
// }catch(e){
// reject(e)
// }
}
//以上都是在同步的基础上进行的,下面处理异步任务
else if(this.PromiseState==="pending"){
//当promise中的任务是异步的时候,执行then方法时,promise的状态可能还没有改变
//当其状态改变的时候再去执行then方法中的回调,但是修改状态的方法中无法调用到then方法中的回调,因此我们可以将then方法的回调保存在实列身上
// this.callback={
// onResolved,
// onRejected
// }使用对象的方式当指定多个回调时,后面的回调会将前面的回调覆盖掉,因此我们使用数组来进行保存
this.callback.push({
// onResolved,
// onRejected
//当为异步是也需要判断then方法返回的结果是否是一个promise对象,因此就不能将onResolved,onRejected直接保存,需要经过处理
onResolved:function(){
public(onResolved)
// try{
// let result=onResolved(that.PromiseResult)
// if(result instanceof Promise){
// result.then((v)=>{
// resolve(v)
// },(r)=>{
// reject(r)
// })
// }else{
// resolve(v)
// }
// }catch(e){
// reject(e)
// }
},
onRejected:function(){
public(onRejected)
// try{
// let result=onRejected(that.PromiseResult)
// if(result instanceof Promise){
// result.then((v)=>{
// resolve(v)
// },(r)=>{
// reject(r)
// })
// }else{
// resolve(v)
// }
// }catch(e){
// reject(e)
// }
}
})
}
})
}
定义catch方法
//定义catch方法
Promise.prototype.catch=function(onRejected){
//返回的也是一个promise对象,因为已经定义了then方法,因此直接调用
return this.then(undefined,onRejected)
}
定义resolve方法
Promise.resolve=function(value){
//返回的也是promise对象
return new Promise((resolve,reject)=>{
if(value instanceof Promise){
value.then(v=>{
resolve(v)
},r=>{
reject(r)
})
}else{
resolve(value)
}
})
}
定义reject方法
//定义promise.reject方法,返回的永远是一个失败的promise
Promise.reject=function(err){
return new Promise((resolve,reject)=>{
reject(err)
})
}```
**定义all方法**
```js
//promise.all方法
Promise.all=function(promises){
//返回一个promise对象
return new Promise((resolve,reject)=>{
let count=0;
let arr=[];
for(let i=0;i<promises.length;i++){
promises[i].then(v=>{
//得知对象的状态是成功
count++;
// arr.push(v) push方法无法和传入的数组方法数据保持一致
arr[i]=v;
if(count===promises.length){
resolve(v)
}
},r=>{
reject(r)
})
}
})
}
定义race方法
//promise.race方法的定义
Promise.race=function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(v=>{
resolve(v)
},r=>{
reject(r)
})
}
})
}
all方法和race方法的区别在于,all需要传入的数组中的promise对象全部成功才会返回成功的结果放在数组中,且数组中结果的顺序和原来数组中的顺序一一对应,一旦有一个失败的就会返回第一个失败的结果。而race的结果是最先成功的那个promise返回的结果,该结果不一定是发送请求时数组中的第一个。
//测试
const p=new Promise((resolve,reject)=>{
// resolve("ok")
reject("error")
// throw "err"
// setTimeout(()=>{
// reject("ok")
// },2000)
})
console.log(p);
const res= p.then((value)=>{
// console.log(value);
return "holle"
})
const a=p.catch(e=>{
console.log(e);
})
console.log(res,a);//当then方法中没有设置返回值时result为undefined。
//用对象保存回调该then方法的回调会覆盖掉上面的回调,因此只会执行下面这个回调,因此需要使用数组来保存回调
// p.then((value)=>{
// alert(value);
// },(err)=>{
// alert(err);
// })