美文网首页前端笔记
手动实现一个promise

手动实现一个promise

作者: 小虫along | 来源:发表于2020-05-07 12:02 被阅读0次

    整体流程

    先定义整体结构
    实现Promise构造函数
    实现promise.then
    实现promise.catch
    实现promise.resovle
    实现promise.reject
    实现promise.all
    实现promise.race

    1.定义整体结构

    先写出构造函数,将Promise向外暴露

    /*
    自定义Promise函数模块:IIFE
     */
    
    (function (window) {
        /*
        Promise构造函数
        executor:执行器函数
         */
        function Promise(executor) {
    
        }
    
        // 向外暴露Promise
        window.Promise = Promise
    })()
    

    添加Promise原型对象上的方法

    /*
        Promise原型对象的then
        指定一个成功/失败的回调函数
        返回一个新的promise对象
         */
        Promise.prototype.then = function(onResolved,onRejected){
    
        }
    
        /*
        Promise原型对象的.catch
        指定一个失败的回调函数
        返回一个新的promise对象
         */
        Promise.prototype.catch = function(onRejected){
    
        }
    

    添加Promise函数对象上的方法

    /*
        Promise函数对象的resovle方法
        返回一个指定结果的promise对象
         */
        Promise.resolve = function(value){
    
        }
    
        /*
        Promise函数对象的reject方法
        返回一个指定reason的失败状态的promise对象
        */
        Promise.reject = function(value){
    
        }
    
        /*
        Promise函数对象的all方法
        返回一个promise对象,只有当所有promise都成功时返回的promise状态才成功
        */
        Promise.all = function(value){
    
        }
    
        /*
        Promise函数对象的race方法
        返回一个promise对象,状态由第一个完成的promise决定
        */
        Promise.race = function(value){
    
        }
    

    2. 实现Promise构造函数

    众所周知,构造函数里由resolve和reject方法,而且这两个方法会被传入executor,并且executor立即同步执行

     /*
        Promise构造函数
        executor:执行器函数
         */
        function Promise(executor) {
    
            function resovle() {
    
            }
            function reject() {
    
            }
    
            // 立即同步执行executor
            executor(resovle,reject)
        }
    

    家喻户晓的是,每个promise都有一个状态可能为pending或resolved,rejected。因此需要添加个status,此外,当我们这样使用Promise的时候,

    // 例1
    var promise = new Promise((resovle,reject)=>{
        
    })
    
    promise.then(resolve=>{},reject=>{})
    

    这时执行到then,promise的状态还是pending,这时要把值和then里面的回调函数保存起来,所以需要个data和callbacks

    function Promise(executor) {
    
            var self = self
    
            self.status = 'pending' // 给promise对象指定status属性,初始值为pending
            self.data = undefined // 给promise对象指定一个存储结果的data
            self.callbacks = []  // 每个元素的结构:{onResolved(){},onRejected(){}}
    
    
            function resovle() {
    
            }
            function reject() {
    
            }
    
            // 立即同步执行executor
            executor(resovle,reject)
        }
    

    妇孺皆知的是,在上面的例子1的基础上,当我们执行resovle(value)时,

    // 例2
    var promise = new Promise((resolve,reject)=>{
        setTimeout(function () {
            resolve(1)
        })
    })
    
    promise.then(resolve=>{},reject=>{})
    

    会把promise对象的status改为resovle,并且把value保存到data,然后执行之前保存的callbacks(上面说过当执行到then时,发现当前的promise是pending状态,会把then里的回调函数保存到promise的callbacks里)。

    
    function resolve(value) {
                // 如果当前状态不是pending,则不执行
                if(self.status !== 'pending'){
                    return
                }
                // 将状态改为resolved
                self.status = 'resolved'
                // 保存value的值
                self.data = value
    
                // 如果有待执行的callback函数,立即异步执行回调函数onResolved
                if (self.callbacks.length>0){
                    setTimeout(()=>{
                        self.callbacks.forEach(callbackObj=>{
                            callbackObj.onResolved(value)
                        })
                    })
                }
            }
    

    我们还知道,promise的状态只能改变一次,因此当执行resolve的时候要判断是不是promise是不是pending的状态,否则是不能执行的

    function resolve(value) {
                // 如果当前状态不是pending,则不执行
                if(this.status !== 'pending'){
                    return 
                }
                // 将状态改为resolved
                this.status = 'resolved'
                // 保存value的值
                this.data = value
    
                // 如果有待执行的callback函数,立即异步执行回调函数onResolved
                if (this.callbacks.length>0){
                    setTimeout(()=>{
                        this.callbacks.forEach(callbackObj=>{
                            callbackObj.onResolved(value)
                        })
                    })
                }
            }
    

    异曲同工之妙的是reject方法也是这个道理,因此这里无需赘述

    function reject(value) {
                // 如果当前状态不是pending,则不执行
                if(self.status !== 'pending'){
                    return
                }
                // 将状态改为resolved
                self.status = 'rejected'
                // 保存value的值
                self.data = value
    
                // 如果有待执行的callback函数,立即异步执行回调函数onResolved
                if (self.callbacks.length>0){
                    setTimeout(()=>{
                        self.callbacks.forEach(callbackObj=>{
                            callbackObj.onRejected(value)
                        })
                    })
                }
            }
    

    我们又知道,当在执行executor的时候,如果执行异常的话,这个promise的状态会直接执行reject方法。

    // 例 3
    var promise = new Promise((resolve,reject)=>{
    
        执行到这里出错了
    
        setTimeout(function () {
            resolve(1)
        })
    })
    

    要实现这个功能,我们可以在executor外让try catch来捕获

            try{
                // 立即同步执行executor
                executor(resolve,reject)
            }catch (e) { // 如果执行器抛出异常,promise对象变为rejected状态
                reject(e)
            }
    

    好了,现在来测试一下,为了测试,我们需要简单的实现下then,让它往callbacks里push then里的回调函数

      Promise.prototype.then = function(onResolved,onRejected){
            // 假设当前状态还是pending状态,将回调函数保存起来
            this.callbacks.push({
                onResolved,
                onRejected
            })
        }
    

    好了,现在测试下,发现成功。

     // 例4
     let promise = new Promise((resolve,reject)=>{
            
            setTimeout(function () {
                // resolve(1)
                reject(1)
            },100)
        })
    
        promise.then(
            value=>{
                console.log("onResolved:",value);
            },
            reason=>{
                console.log("onRejected:",reason);
            }
        )
    

    3. 实现then方法

    尽人皆知的时,执行到then时,promise可能会是pending状态,此时就要把then里的回调函数保存起来,也可能会是resolved或者rejected状态,此时要执行onResolved或onRejected方法。

    Promise.prototype.then = function(onResolved,onRejected){
    
            var self = this
    
            if(self.status === 'pending'){
                // promise当前状态还是pending状态,将回调函数保存起来
                self.callbacks.push({
                    onResolved(){onResolved(self.data)},
                    onRejected(){onRejected(self.data)}
                })
            }else if(self.status === 'resolved'){
                setTimeout(()=>{
                    onResolved(self.data)
                })
            }else{
                setTimeout(()=>{
                    onResolved(self.data)
                })
            }
    
        }
    
    

    而且我们知道,执行完then是要返回一个新的promise的,而新的promise的状态则由当前then的执行结果来确定。

    Promise.prototype.then = function(onResolved,onRejected){
    
            var self = this
    
            return new Promise((resolve,reject)=>{
                if(self.status === 'pending'){
                    // promise当前状态还是pending状态,将回调函数保存起来
                    self.callbacks.push({
                        onResolved(){onResolved(self.data)},
                        onRejected(){onRejected(self.data)}
                    })
                }else if(self.status === 'resolved'){
                    setTimeout(()=>{
                        onResolved(self.data)
                    })
                }else{
                    setTimeout(()=>{
                        onResolved(self.data)
                    })
                }
            })
    
        }
    

    当当前的promise状态为resolved的时候,则当前执行的onresolved函数由三种情况
    如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。

    // 例5
        let promise = new Promise((resolve,reject)=>{
            resolve(1)
        })
    
        promise.then(
            value=>{
                return value
            },
            reason=>{
                console.log("onRejected:",reason);
            }
        )
    

    因此,我们可以这样实现

    Promise.prototype.then = function(onResolved,onRejected){
    
            var self = this
    
            return new Promise((resolve,reject)=>{
                if(self.status === 'pending'){
                    // promise当前状态还是pending状态,将回调函数保存起来
                    self.callbacks.push({
                        onResolved(){onResolved(self.data)},
                        onRejected(){onRejected(self.data)}
                    })
                }else if(self.status === 'resolved'){
                    setTimeout(()=>{
                        const result = onResolved(self.data)
                        if (result instanceof Promise){
    
                        } else {
                        // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                            resolve(result)
                        }
                    })
                }else{
                    setTimeout(()=>{
                        onResolved(self.data)
                    })
                }
            })
    
        }
    

    如果回调函数返回的是promise,return的promise的结果就是这个promise的结果,如代码所示,我们返回一个新的promise。这个新的promise执行了resolve,因此返回的promise的状态是resolved的

    // 例6
     let promise = new Promise((resolve,reject)=>{
            resolve(1)
        })
    
        promise.then(
            value=>{
                return new Promise((resolve,reject)=>{
                    resolve(2)
                })
            },
            reason=>{
                console.log("onRejected:",reason);
            }
        )
    

    因此我们可以这样实现

    Promise.prototype.then = function(onResolved,onRejected){
    
            var self = this
    
            return new Promise((resolve,reject)=>{
                if(self.status === 'pending'){
                    // promise当前状态还是pending状态,将回调函数保存起来
                    self.callbacks.push({
                        onResolved(){onResolved(self.data)},
                        onRejected(){onRejected(self.data)}
                    })
                }else if(self.status === 'resolved'){
                    setTimeout(()=>{
                        const result = onResolved(self.data)
                        if (result instanceof Promise){
                            // 2. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
                            result.then(
                                value => {resolve(value)},
                                reason => {reject(reason)}
                            )
                        } else {
                            // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                            resolve(result)
                        }
                    })
                }else{
                    setTimeout(()=>{
                        onResolved(self.data)
                    })
                }
            })
    
        }
    

    在这里说明一下:

    result.then(
        value => {resolve(value)},
        reason => {reject(reason)}
    )
    

    由于我们在例6中执行了then里的resolve函数, 将会导致value => {resolve(value)},这个回调函数的执行,因此会把即将返回的新的promise的data设置为value,会把状态设置为resolved。

    如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected,我们可以用try catch来实现

    setTimeout(()=>{
        try{
            const result = onResolved(self.data)
            if (result instanceof Promise){
                // 2. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
                result.then(
                    value => {resolve(value)},
                    reason => {reject(reason)}
                )
            } else {
                // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                resolve(result)
            }
        }catch (e) {
          //  3.如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected
            reject(e)
        }
    })
    

    异曲同工之妙的是当当status === 'rejected',道理一样

     setTimeout(()=>{
          try{
              const result = onRejected(self.data)
              if (result instanceof Promise){
                  // 2. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
                  result.then(
                      value => {resolve(value)},
                      reason => {reject(reason)}
                  )
              } else {
                  // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                  resolve(result)
              }
          }catch (e) {
              //  3.如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected
              reject(e)
          }
      })
    

    到这里,我们发现当执行resolve的时候,onResolved(self.data)和onRejected(self.data)执行时也会跟上面一样的结果,可以说执行回调函数都要做以上判断,因此我们要将

    self.callbacks.push({
        onResolved(){onResolved(self.data)},
        onRejected(){onRejected(self.data)}
    })
    

    改成

    if(self.status === 'pending'){
    // promise当前状态还是pending状态,将回调函数保存起来
    self.callbacks.push({
        onResolved(){
            try{
                const result = onResolved(self.data)
                if (result instanceof Promise){
                    // 2. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
                    result.then(
                        value => {resolve(value)},
                        reason => {reject(reason)}
                    )
                } else {
                    // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                    resolve(result)
                }
            }catch (e) {
                //  3.如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected
                reject(e)
            }
        },
    

    到此,我们发现,相同的代码太多了,因此有必要封装一下

    function handle(callback) {
        try{
            const result = callback(self.data)
            if (result instanceof Promise){
                // 2. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
                result.then(
                    value => {resolve(value)},
                    reason => {reject(reason)}
                )
            } else {
                // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                resolve(result)
            }
        }catch (e) {
            //  3.如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected
            reject(e)
        }
    }
    

    这样以来就清爽了很多

    Promise.prototype.then = function(onResolved,onRejected){
    
            var self = this
    
            return new Promise((resolve,reject)=>{
               /*
                调用指定回调函数的处理,根据执行结果。改变return的promise状态
                 */
                function handle(callback) {
                    try{
                        const result = callback(self.data)
                        if (result instanceof Promise){
                            // 2. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
                            result.then(
                                value => {resolve(value)},
                                reason => {reject(reason)}
                            )
                        } else {
                            // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                            resolve(result)
                        }
                    }catch (e) {
                        //  3.如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected
                        reject(e)
                    }
                }
                if(self.status === 'pending'){
                    // promise当前状态还是pending状态,将回调函数保存起来
                    self.callbacks.push({
                        onResolved(){
                            handle(onResolved)
                        },
                        onRejected(){
                            handle(onRejected)
                        }
                    })
                }else if(self.status === 'resolved'){
                    setTimeout(()=>{
                        handle(onResolved)
                    })
                }else{ // 当status === 'rejected'
                    setTimeout(()=>{
                        handle(onRejected)
                    })
                }
            })
    
        }
    
    

    另外,我们还知道,promise会发生直传透,例如

    Promise.resolve(1)
      .then(2)
      .then(Promise.resolve(3))
      .then(console.log)
    

    运行结果: 1
    解释:.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。值传透可以理解为,当传入then的不是函数的时候,这个then是无效的。

    因此,要实现直传透这个特性,我们可以这样实现

    添加这两句来判断要不要发生值传透

    onResolved = typeof onResolved === 'function'? onResolved: value => value
    onRejected = typeof onRejected === 'function'? onRejected: reason => {throw reason}
    
     Promise.prototype.then = function(onResolved,onRejected){
            onResolved = typeof onResolved === 'function'? onResolved: value => value
            onRejected = typeof onRejected === 'function'? onRejected: reason => {throw reason}
            var self = this
    
            return new Promise((resolve,reject)=>{
    
                /*
                调用指定回调函数的处理,根据执行结果。改变return的promise状态
                 */
                function handle(callback) {
                    try{
                        const result = callback(self.data)
                        if (result instanceof Promise){
                            // 2. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果
                            result.then(
                                value => {resolve(value)},
                                reason => {reject(reason)}
                            )
                        } else {
                            // 1. 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。
                            resolve(result)
                        }
                    }catch (e) {
                        //  3.如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected
                        reject(e)
                    }
                }
                if(self.status === 'pending'){
                    // promise当前状态还是pending状态,将回调函数保存起来
                    self.callbacks.push({
                        onResolved(){
                            handle(onResolved)
                        },
                        onRejected(){
                            handle(onRejected)
                        }
                    })
                }else if(self.status === 'resolved'){
                    setTimeout(()=>{
                        handle(onResolved)
                    })
                }else{ // 当status === 'rejected'
                    setTimeout(()=>{
                        handle(onRejected)
                    })
                }
            })
    
        }
    
      
    

    3.实现catch方法
    妇孺皆知的是,catch方法的作用跟then里的第二歌回调函数一样,因此我们可以这样来实现

    Promise.prototype.catch = function(onRejected){
        return this.then(undefined,onRejected)
    }
    

    天啊,居然这么简单

    4. 实现Promise.resolve

    我们都知道,Promise.resolve方法可以传三种值

    不是promise
    成功状态的promise
    失败状态的promise

        Promise.resolve(1)
        Promise.resolve(Promise.resolve(1))
        Promise.resolve(Promise.reject(1))
    

    实际上跟实现上面的then时有点像

    Promise.resolve = function(value){
      return new Promise((resolve,reject)=>{
          if (value instanceof Promise){
              // 如果value 是promise
              value.then(
                  value => {resolve(value)},
                  reason => {reject(reason)}
              )
          } else{
              // 如果value不是promise
              resolve(value)
          }
    
      }
    
    }
    

    5.实现Promise.reject

    实现这个比较简单,返回一个状态为rejected的promise就好了

    /*
    Promise函数对象的reject方法
    返回一个指定reason的失败状态的promise对象
    */
    Promise.reject = function(reason){
        return new Promise((resolve,reject)=>{
            reject(reason)
        })
    }
    

    6.实现Promise.all

    我们知道,这个方法会返回一个promise

        /*
        Promise函数对象的all方法
        返回一个promise对象,只有当所有promise都成功时返回的promise状态才成功
        */
        Promise.all = function(promises){
            return new Promise((resolve,reject)=>{
               
            })
        }
    

    而这个promise的状态由遍历每个promise产生的结果决定

        /*
        Promise函数对象的all方法
        返回一个promise对象,只有当所有promise都成功时返回的promise状态才成功
        */
        Promise.all = function(promises){
            return new Promise((resolve,reject)=>{
                // 遍历promises,获取每个promise的结果
                promises.forEach((p,index)=>{
                    
                })
            })
        }
    

    有两种结果:
    遍历到有一个promise是reject状态,则直接返回的promise状态为rejected

     Promise.all = function(promises){
            return new Promise((resolve,reject)=>{
                // 遍历promises,获取每个promise的结果
                promises.forEach((p,index)=>{
                    p.then(
                        value => {
        
                        },
                        reason => { //只要有一个失败,return的promise状态就为reject
                            reject(reason)
                        }
                    )
                })
            })
        }
    

    遍历所有的promise的状态都为resolved,则返回的promise状态为resolved,并且还要每个promise产生的值传递下去

       Promise.all = function(promises){
          const values = new Array(promises.length)
          var resolvedCount = 0 //计状态为resolved的promise的数量
          return new Promise((resolve,reject)=>{
              // 遍历promises,获取每个promise的结果
              promises.forEach((p,index)=>{
                  p.then(
                      value => {
                          // p状态为resolved,将值保存起来
                          values[index] = value
                          resolvedCount++;
                          // 如果全部p都为resolved状态,return的promise状态为resolved
                          if(resolvedCount === promises.length){
                              resolve(values)
                          }
                      },
                      reason => { //只要有一个失败,return的promise状态就为reject
                          reject(reason)
                      }
                  )
              })
          })
      }
    

    好像可以了,当其实这里还有一个问题,就是all传进去的数组不一定都是promise对象,可能是这样的

    all([p,2,3,p])
    

    因此需要把不是promise的数字包装成promise

     Promise.all = function(promises){
            const values = new Array(promises.length)
            var resolvedCount = 0 //计状态为resolved的promise的数量
            return new Promise((resolve,reject)=>{
                // 遍历promises,获取每个promise的结果
                promises.forEach((p,index)=>{
                    Promise.resolve(p).then(
                        value => {
                            // p状态为resolved,将值保存起来
                            values[index] = value
                            resolvedCount++;
                            // 如果全部p都为resolved状态,return的promise状态为resolved
                            if(resolvedCount === promises.length){
                                resolve(values)
                            }
                        },
                        reason => { //只要有一个失败,return的promise状态就为reject
                            reject(reason)
                        }
                    )
                })
            })
        }
    

    7.实现Promise.race

    这个方法的实现要比all简单很多

      /*
        Promise函数对象的race方法
        返回一个promise对象,状态由第一个完成的promise决定
        */
        Promise.race = function(promises){
            return new Promise((resolve,reject)=>{
                // 遍历promises,获取每个promise的结果
                promises.forEach((p,index)=>{
                    Promise.resolve(p).then(
                        value => {
                            // 只要有一个成功,返回的promise的状态九尾resolved
                            resolve(value)
    
                        },
                        reason => { //只要有一个失败,return的promise状态就为reject
                            reject(reason)
                        }
                    )
                })
            })
        }
    

    相关文章

      网友评论

        本文标题:手动实现一个promise

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