美文网首页让前端飞
深度解析利用ES6进行Promise封装总结

深度解析利用ES6进行Promise封装总结

作者: a333661d6d6e | 来源:发表于2019-02-14 15:32 被阅读5次

    这篇文章主要介绍了如何利用ES6进行Promise封装总结,文中通过示例代码介绍的非常详细,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。

    原生Promise解析

    简介

    • promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和强大。
    • promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从语法上来说,Promise是一个对象,从它可以获取异步操作的消息,Promise提供统一的API,各种异步操作都可以用同样的方法进行处理

    特点

    对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:Pendding、fulfilled、rejected。只有异步操作的结果,可以决定当前是哪一种状态,其他操作都无法改变这个状态。
    一旦状态改变,就不会在变,任何时候都可以得到这个结果,只有两种可能:从Pendding变为fulfilled和从Pendding变为rejected。只要这两种情况发生,状态就凝固了,会一直保持这个结果,这时就称为resolved。
    1.利用es6进行Promise封装

    2.处理同步任务

    3.原生方法调用方式

    new Promise((resolve,reject)=>{
      resolve(1)
    }).then(res=>{
      console.log(res) //1
    })
    

    同步封装思考
    1.由调用方式可见Promise是一个类
    2.它接收一个回调函数,这个回调函数接受resolve和reject方法作为参数
    3.当状态改变后执行then方法,并将resolve或reject的结果作为then方法接受回调函数的参数

    class Mypromise{
      constructor(callback){
        this.status='pendding'
        //成功结果
        this.s_res = null
        // 失败结果
        this.f_res = null
        callback((arg)=>{ // 使用箭头函数this不会丢失
         // 改变状态为成功
         this.status = 'fulfilled'
         this.s_res = arg
        },(arg)=>{
          // 改变状态为失败
          this.status = 'rejected'
          this.f_res = arg 
        })
      }
      then(onresolve,onreject){
        if(this.status === 'fulfilled'){ // 当状态为成功时
          onresolve(this.s_res)
        }else if(this.status === 'rejected'){ // 当状态为失败时
          onreject(this.f_res)
        }//在此我向大家推荐一个前端全栈开发交流圈:619586920  突破技术瓶颈,提升思维能力
      }
    }
    

    处理异步任务

    原生调用方式

    new Promise((resolve,reject)=>{
      setTimeOut(()=>{
        resolve(1)
      },1000)
    }).then(res=>{
      console.log(res)
    })
    

    异步封装思考
    1.根据js执行机制,setTimeOut属于宏任务,then回调函数属于微任务,当主线程执行完成后,会从异步队列中取出本次的微任务先执行。
    2.也就是说,then方法执行时,状态还没有改变,所有我们需要将then方法执行的回调保存起来,等到异步代码执行完成后,在统一执行then方法的回调函数

    class Mypromise{
      constructor(callback){
        this.status='pendding'
        //成功结果
        this.s_res = null
        // 失败结果
        this.f_res = null
        this.query = [] // ++ 
        callback((arg)=>{ // 使用箭头函数this不会丢失
         // 改变状态为成功
         this.status = 'fulfilled'
         this.s_res = arg
         // 当状态改变后,统一执行then方法的回调
         this.query.forEach(item=>{
           item.resolve(arg)
         })//在此我向大家推荐一个前端全栈开发交流圈:619586920  突破技术瓶颈,提升思维能力
        },(arg)=>{
          // 改变状态为失败
          this.status = 'rejected'
          this.f_res = arg 
          // 当状态改变后,统一执行then方法的回调
         this.query.forEach(item=>{
           item.reject(arg)
         })
        })
      }
      then(onresolve,onreject){
        if(this.status === 'fulfilled'){ // 当状态为成功时
          onresolve(this.s_res)
        }else if(this.status === 'rejected'){ // 当状态为失败时
          onreject(this.f_res)
        }else{ // ++ 状态没有改变
          this.query.push({ // 保存回调函数到队列中
            resolve:onresolve,
            reject:onreject
          })//在此我向大家推荐一个前端全栈开发交流圈:619586920  突破技术瓶颈,提升思维能力
        }
      }
    } 
    

    处理链式调用

    原生调用方式

    new Promise((resolve,reject)=>{
      resolve(1)
    }).then(res=>{
      return res
    }).then(res=>{
      console.log(res)
    })//在此我向大家推荐一个前端全栈开发交流圈:619586920  突破技术瓶颈,提升思维能力
    

    链式调用思考

    原生的Promise对象的then方法,返回的也是一个Promise对象,一个新的Promise才能支持链式调用
    下一个then方法可以接受上一个then方法的返回值作为回调函数的参数
    主要考虑上一个then方法的返回值:
    1.Promise对象/具有then方法的对象
    2.其他值
    第一个then方法返回一个Promise对象,它的回调函数接受resFn和rejFN两个回调函数作为参数,把成功状态的处理封装为handle函数,接受成功的结果作为参数
    在handle函数,根据onresolve返回值的不同做出不同的处理

    class Mypromise{
      constructor(callback){
        this.status='pendding'
        //成功结果
        this.s_res = null
        // 失败结果
        this.f_res = null
        this.query = [] // ++ 
        callback((arg)=>{ // 使用箭头函数this不会丢失
         // 改变状态为成功
         this.status = 'fulfilled'
         this.s_res = arg
         // 当状态改变后,统一执行then方法的回调
         this.query.forEach(item=>{
           item.resolve(arg)
         })
        },(arg)=>{
          // 改变状态为失败
          this.status = 'rejected'
          this.f_res = arg 
          // 当状态改变后,统一执行then方法的回调
         this.query.forEach(item=>{
           item.reject(arg)
         })
        })
      }
      then(onresolve,onreject){
        return new Mypromise((resFN,rejFN)=>{
          if(this.status === 'fulfilled'){ // 当状态为成功时
            handle(this.s_res)
          }else if(this.status === 'rejected'){ // 当状态为失败时
            errBack(this.f_res)
          }else{ // ++ 状态没有改变
            this.query.push({ // 保存回调函数到队列中
              resolve:onresolve,
              reject:onreject
            })
          } //在此我向大家推荐一个前端全栈开发交流圈:619586920  突破技术瓶颈,提升思维能力
          function handle(value){
            // 当then方法的onresolve方法有返回值时,保存其返回值,没有使用其保存的值
            let returnVal = onresolve instanceof Function && onresolve(value) || value
            // 如果onresolve方法返回的是promise对象,则调用其then方法
            if(returnVal&&returnVal['then'] instanceof Function){
              returnVal.then(res=>{
                resFN(res)
              },err=>{
                rejFN(err)
              })
            }else{
              resFN(returnVal)
            } 
          }
          function errBack(reason){
            if(onreject instanceof Function){
              let returnVal = reject(reason)
              if(typeof returnVal !== 'undenfined' && returnVal['then'] instanceof Function){
                returnVal.then(res=>{
                  resFN(res)
                },err=>{
                  rejFN(err)
                })
              }else{
                resFN(returnVal)
              }
            }else{
              rejFN(reason)
            }
          }
        })
      }
    } 
    

    Promise.all和Promise.race方法

    原生调用方式
    Promise.all方法接受一个数组,数组中的每一项都是一个Promise实例,只有数组中的所有Promise实例的状态都变为fulfilled时,此时整个状态才会变成fulfilled,此时数组中所有Promise实例的返回值组成一个新的数组,进行传递。
    Promise.race方法和Promise.all方法一样,如果不是Promise实例,就会先调用Promise.resolve方法,将参数转为Promise实例,在进行下一步处理。
    只要数组中有一个参数的状态变为fulfilled就会进行传递

    // 将现有对象转换为Promise对象
      Mypromise.resolve = (arg)=>{
        if(typeof arg == 'undefined' || arg==null){ // 不带有任何参数
          return new Mypromise(resolve=>{
            resolve(arg)
          })
        }else if(arg instanceof Mypromise){ // 是一个Mypromise实例
          return arg
        }else if(arg['then'] instanceof Function){ // 具有then方法的对象
          return new Mypromise((resolve,reject)=>{
            arg.then(res=>{
              resolve(res)
            },err=>{
              reject(err)
            })//在此我向大家推荐一个前端全栈开发交流圈:619586920  突破技术瓶颈,提升思维能力
          })
        }else{ // 参数不是具有then方法的对象,或根本不是对象
          return new Mypromise(resolve=>{
            resolve(arg)
          }) 
        }
      }
      Mypromise.all = (arr)=>{
        if(!Array.isArray(arr)){
          throw new TypeError('参数必须是一个数组')
        }
        return new Mypromise((resolve,reject)=>{
          let i=0,result=[]
          next()
          functon next(){
            // 如果不是Mypromise实例需要转换
            Mypromise.resolve(arr[i]).then(res=>{
              result.push(res)
              i++
              if(i===arr.length){
                resolve(result)
              }else{
                next()
              }
            },reject)
          }
        })
      }//在此我向大家推荐一个前端全栈开发交流圈:619586920  突破技术瓶颈,提升思维能力
      Mypromise.race = (arr)=>{
        if(!Array.isArray(arr)){
          throw new TypeError('参数必须是一个数组')
        }
        return new Mypromise((resolve,reject)=>{
          let done = false
          arr.forEach(item=>{
            Mypromise.resolve(item).then(res=>{
              if(!done){
                resolve(res)
                done = true
              }
            },err=>{
              if(!done){
                reject(res)
                done = true
              }
            })
          })
        })
      }
    

    处理Mypromise状态确定不能改变的特性
    在重写callback中的resolve和reject方法执行前,先判断状态是否为'pendding'

    结语

    感谢您的观看,如有不足之处,欢迎批评指正。

    获取资料

    本次给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
    对web开发技术感兴趣的同学,欢迎加入Q群:619586920,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。
    最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

    相关文章

      网友评论

        本文标题:深度解析利用ES6进行Promise封装总结

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