美文网首页
promise的基本用法以及实现原理

promise的基本用法以及实现原理

作者: 仔崽06 | 来源:发表于2020-10-11 18:50 被阅读0次

    1.promise是什么?

    promise是异步编程的一种解决方案,解决多个异步方法串行的问题,比如回调地狱等.所谓的promise,简单地说就是一个容器,里面保存着某个未来才会结束的事件,从语法说promise是一个对象,从他可以获取异步操作的消息。promise提供统一的api,各种操作都可以用相同的方法进行处理.

    2.promise的特点

    1.对象的状态不收外界影响,promise对象代表一个异步操作,有三种状态pending(进行中),fulfilled(已成功)和rejected(已失败)。只有一步的操作结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    2.一旦状态改变,就不会在编,任何时候都可以得到这个结果。promise对象的状态改变只有两种可能:从pending变为fulfilled或从pending变为rehected.

    2.基本用法

    ES6规定,promise对象是一个构造函数,用来生成Promise实例。
    promise默认传入exectutor执行器 立即执行。
    promise提供两个方法reslove和reject.
    promise实例生成后,可以用then方法分别指定resloved状态和rejected状态的回调函数.

    let p1=new Promise((reslove,reject)=>{
        if(true){
            reslove('成功')
        }else{
            reject('失败')
        }
    })
    p1.then((data)=>{
        //成功的回调
        console.log(data)
    },(err)=>{
        //失败的回调
        console.log(err)
    })
    

    基本用法的简单实现

    //1.exectutor执行器 立即执行
    //三种状态默认是等待态 resolve成功态  reject失败态
    
    const PENDING='PENDING'
    const RESOLVE='RESOLVE'
    const REJECT='REJECT'
    class Promise{
        constructor(exectutor){
            //成功状态的取值
            this.success_val=undefined;
            //失败状态的取值
            this.error_val=undefined;
            //状态
            this.status=PENDING;
            //成功回调
            let resolve=(val)=>{
                //判断如果是等待态 将状态赋值 不能再修改状态
                if(this.status===PENDING){
                    this.success_val=val;
                    this.status=RESOLVE;
                }
            }
            //失败回调
            let reject=(err)=>{
                //同上
                if(this.status===PENDING){
                    this.error_val=err;
                    this.status=REJECT
                }
            }
            try{
               exectutor(resolve,reject)
            }catch(err){
                //如果是 throw err直接手动调用reject
               reject(err)
            }
        }
        then(successFn,errFn){
            //then会传入两个回调函数 一个成功一个失败
            //如果状态是成功态 successFn执行
            if(this.status===RESOLVE){
                successFn(this.success_val)
            }
            //反之
            if(this.status===REJECT){
                errFn(this.error_val)
            }
        }
    }
    

    promise里面setTimeout几秒后resolve或者reject结果,异步操作,这时候需要用到发布订阅模式.

    const Promise=require('./promise.js')
    let p1=new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('成功')
        },3000)
    })
    p1.then((data)=>{
        console.log(data)
    },(err)=>{
        console.log(err)
    })
    
    //此时promise应该是等待态
    const PENDING='PENDING'
    const RESOLVE='RESOLVE'
    const REJECT='REJECT'
    class Promise{
        constructor(exectutor){
            //成功状态的取值
            this.success_val=undefined;
            //失败状态的取值
            this.error_val=undefined;
            //状态
            this.status=PENDING;
            //成功数组里存放执行器
            this.success_arr=[];
            //失败数组里存放执行器
            this.err_arr=[];
            //成功回调
            let resolve=(val)=>{
                //判断如果是等待态 将状态赋值 不能再修改状态
                if(this.status===PENDING){
                    this.success_val=val;
                    this.status=RESOLVE;
                    //promise 成功态后只需依次执行this.success里的函数即可
                    this.success_arr.forEach(fn=>{
                        fn()
                    })
                }
            }
            //失败回调
            let reject=(err)=>{
                //同上
                if(this.status===PENDING){
                    this.error_val=err;
                    this.status=REJECT
                    this.err_arr.forEach(fn=>{
                        fn()
                    })
                }
            }
            try{
               exectutor(resolve,reject)
            }catch(err){
                //如果是 throw err直接手动调用reject
               reject(err)
            }
        }
        then(successFn,errFn){
            //then会传入两个回调函数 一个成功一个失败
            //如果状态是成功态 successFn执行
            if(this.status===RESOLVE){
                successFn(this.success_val)
            }
            //反之
            if(this.status===REJECT){
                errFn(this.error_val)
            }
            //有异步操作这时promise的状态为pedding
            if(this.status===PENDING){
                this.success_arr.push(()=>{
                    //添加一个函数代码可拓展 增加别的逻辑 successFn执行的时候 当前状态已改为成功态 this.success的值已经改变
                    successFn(this.success_val)
                })
                this.err_arr.push(()=>{
                    errFn(this.error_val)
                })
            }
        }
    }
    
    module.exports=Promise;
    

    promise中的链式调用类似于jquery的链式调用,不同的是jquery返回的是this,promise返回的是一个新的promise。

    1. then放方法中(成功或者失败)只要不是返回一个promise,都会将结果返回到下一个then中成功的回调函数.
    let p1=new Promise((resolve,reject)=>{
        resolve('成功')
    })
    p1.then((data)=>{
        console.log(data) //成功
        return 2
    },(err)=>{
        console.log(err)
    }).then((data)=>{
        console.log(data) //2
    },(err)=>{
        console.log(err)
    })
    
    let p1=new Promise((resolve,reject)=>{
        reject('失败')
    })
    p1.then((data)=>{
        return 2
    },(err)=>{
        return err
    }).then((data)=>{
        console.log('success',data)  //success 失败
    },(err)=>{
        console.log('err',err)
    })
    
    1. 如果then方法中抛出异常(throw new Error),会将结果返回到下一个then的失败的回调函数.
    let p1=new Promise((resolve,reject)=>{
        resolve('成功')
    })
    p1.then((data)=>{
        throw new Error('成功回调里 抛出异常')
    },(err)=>{
        return err
    }).then((data)=>{
        console.log('success',data) 
    },(err)=>{
        console.log('err',err) //err Error: 成功回调里 抛出异常
    })
    
    1. 如果返回一个promise,会将这个promise的返回结果,作为下一次then里成功或者失败.
    //新promise成功返回
    let p1=new Promise((resolve,reject)=>{
        resolve('成功')
    })
    p1.then((data)=>{
        return new Promise((resolve,reject)=>{
            resolve('新promise成功')
        })
    },(err)=>{
        return err
    }).then((data)=>{
        console.log('success',data)  //success 新promise成功
    },(err)=>{
        console.log('err',err)
    })
    
    //新promise失败返回
    let p1=new Promise((resolve,reject)=>{
        resolve('成功')
    })
    p1.then((data)=>{
        return new Promise((resolve,reject)=>{
            reject('新promise失败')  //throw new Error('新promise失败') 同理
        })
    },(err)=>{
        return err
    }).then((data)=>{
        console.log('success',data)  
    },(err)=>{
        console.log('err',err) //err 新promise失败
    })
    
    1. catch错误捕获,先找距离自己近的如果没有错误捕获,会找到最终的catch方法.如果catch返回一个普通值,会将catch结果返回到下一次then的成功回调中。
    let p1=new Promise((resolve,reject)=>{
        resolve('成功')
    })
    p1.then((data)=>{
        return new Promise((resolve,reject)=>{
           reject('新promise失败')
        })
    },(err)=>{
        return err
    }).then((data)=>{
        console.log('success',data)  
    },(err)=>{
        console.log('err',err) //err 新promise失败
    }).catch(err=>{
        console.log('catch err',err) //会找最近的 err回调 如果前面定义了err回调 不会走catch错误被捕获
    })
    
    
    //前面没有错误捕获会走到catch方法
    let p1=new Promise((resolve,reject)=>{
        resolve('成功')
    })
    p1.then((data)=>{
        return new Promise((resolve,reject)=>{
           reject('新promise失败')
        })
    },(err)=>{
        return err
    }).then((data)=>{
        console.log('success',data)  
    }).catch(err=>{
        console.log('catch err',err)  //catch err 新promise失败
    })
    
    //如果catch返回一个普通值,会将catch结果返回到下一次then的成功回调中
    let p1=new Promise((resolve,reject)=>{
        resolve('成功')
    })
    p1.then((data)=>{
        return new Promise((resolve,reject)=>{
           reject('新promise失败')
        })
    },(err)=>{
        return err
    }).then((data)=>{
        console.log('success',data)  
    }).catch(err=>{
        console.log('catch err',err)
        return err
    }).then(data=>{
        console.log('catch success',data) //catch success 新promise失败
    })
    

    基于以上特点实现一个完整的promise

    const PENDING='PENDING'
    const RESOLVE='RESOLVE'
    const REJECT='REJECT'
    function resolvePromise(promise2,x,resolve,reject){
        //循环引用报错 是同一个对象
        if(promise2===x){
            return reject(new TypeError('Chaining cycle detected for promise'));
        }
        //防止多次调用
        let called;
        //判读then的返回结果是普通值还是promise
        if(typeof x!==null&&(typeof x==='function' || typeof x==='object')){
            try{
                let then=x.then;
                //如果是promise 
                if(typeof then==='function'){
                    //成功的回调函数
                     then.call(x,data=>{
                        if(called) return;
                        called=true;
                        //如果返回的还是promise 继续解析,递归调用
                        resolvePromise(promise2,data,resolve,reject)
                    },err=>{
                        if(called) return;
                        called=true;
                        reject(err)
                    })
                }else{
                    //如果是对象 
                    resolve(x)
                }
            }catch(err){
                //如果then抛出异常直接调用reject
                if(called) return;
                called=true;
                reject(err)
            }
        }else{
            //普通值直接返回x
            resolve(x)
        }
    }
    class Promise{
        constructor(exectutor){
            //成功状态的取值
            this.success_val=undefined;
            //失败状态的取值
            this.error_val=undefined;
            //状态
            this.status=PENDING;
            //成功数组里存放执行器
            this.success_arr=[];
            //失败数组里存放执行器
            this.err_arr=[];
            //成功回调
            let resolve=(val)=>{
                //判断如果是等待态 将状态赋值 不能再修改状态
                if(this.status===PENDING){
                    this.success_val=val;
                    this.status=RESOLVE;
                    //promise 成功态后只需依次执行this.success里的函数即可
                    this.success_arr.forEach(fn=>{
                        fn()
                    })
                }
            }
            //失败回调
            let reject=(err)=>{
                //同上
                if(this.status===PENDING){
                    this.error_val=err;
                    this.status=REJECT
                    this.err_arr.forEach(fn=>{
                        fn()
                    })
                }
            }
            try{
               exectutor(resolve,reject)
            }catch(err){
                //如果是 throw err直接手动调用reject
               reject(err)
            }
        }
        then(successFn,errFn){
            //判断 如果successFn不是一个函数 直接将结果返回 防止报错
            successFn= typeof successFn==='function' ? successFn:v=>v 
            errFn=typeof errFn==='function' ? errFn:err=>{throw err}
            //首先每次promise.then会返回一个新的promise
            let promise2=new Promise((resolve,reject)=>{
                if(this.status===RESOLVE){
                    //拿到promise成功回调执行后的结果 判断是否是promise还是普通值.此时promise2还没有生成 需要异步执行 setTimeout
                     setTimeout(()=>{
                         //如果抛出异常 直接就reject返回错误结果
                         try{
                            let x=successFn(this.success_val)
                            resolvePromise(promise2,x,resolve,reject)
                         }catch(err){
                            reject(err)
                         }
                        
                     },0) //默认最少0.4毫秒执行
                }
                //反之
                if(this.status===REJECT){
                    setTimeout(()=>{
                        //如果抛出异常 直接就reject返回错误结果
                        try{
                           let x=errFn(this.error_val)
                           resolvePromise(promise2,x,resolve,reject)
                        }catch(err){
                           reject(err)
                        }
                       
                    },0) //默认最少0.4毫秒执行
                }
                //有异步操作这时promise的状态为pedding
                if(this.status===PENDING){
                    this.success_arr.push(()=>{
                        //添加一个函数代码可拓展 增加别的逻辑 successFn执行的时候 当前状态已改为成功态 this.success的值已经改变
                        try{
                            let x=successFn(this.success_val)
                            resolvePromise(promise2,x,resolve,reject)
                         }catch(err){
                            reject(err)
                         }
                    })
                    this.err_arr.push(()=>{
                        try{
                            let x=errFn(this.error_val)
                            resolvePromise(promise2,x,resolve,reject)
                         }catch(err){
                            reject(err)
                         }
                    })
                }
            }) 
           // 创建一个新的promise并返回
           return promise2;
        }
    }
    
    module.exports=Promise;
    

    catch实现

    catch(errFn){
      return this.then(null,errFn)
    }
    

    finally的实现

     //finally
    finally(fn){
        this.then(value=>{
              fn()
              return value
         },err=>{
              fn()
              throw err
         })
     }
    

    相关文章

      网友评论

          本文标题:promise的基本用法以及实现原理

          本文链接:https://www.haomeiwen.com/subject/hsynuktx.html