这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

1. 定义整体结构

  1. 先写出构造函数,将Promise向外暴露
/*自定义Promise函数模块:IIFE */(function (window) {    /*    Promise构造函数    executor:执行器函数     */    function Promise(executor) {    }    // 向外暴露Promise    window.Promise = Promise})()
  1. 添加Promise原型对象上的方法
 /*    Promise原型对象的then    指定一个成功/失败的回调函数    返回一个新的promise对象     */    Promise.prototype.then = function(onResolved,onRejected){    }    /*    Promise原型对象的.catch    指定一个失败的回调函数    返回一个新的promise对象     */    Promise.prototype.catch = function(onRejected){    }
  1. 添加Promise函数对象上的方法
/*    Promise函数对象的resovle方法    返回一个指定结果的promise对象     */    Promise.resolve = function(value){    }    /*    Promise函数对象的reject方法    返回一个指定reason的失败状态的promise对象    */    Promise.reject = function(value){    }    /*    Promise函数对象的all方法    返回一个promise对象,只有当所有promise都成功时返回的promise状态才成功    */    Promise.all = function(0value){    }    /*    Promise函数对象的race方法    返回一个promise对象,状态由第一个完成的promise决定    */    Promise.race = function(value){    }

通过上面的注释可以知道。不管是Promise原型对象上的方法还是Promise函数对象上的方法,它们的执行结果都将返回一个Promise对象

2. 实现Promise构造函数

我们看看我们是怎么使用Promise的

const promiseA = new Promise( (resolve,reject) => {    resolve(777);});
  1. 我们传入了一个函数,而且这个函数被立即执行,不仅如此,这个函数还会立即执行resolve和reject。说明构造函数里有resolve和reject方法。因此我们可以初步实现:
    /*    Promise构造函数    executor:执行器函数     */    function Promise(executor) {        function resovle() {        }        function reject() {        }        // 立即同步执行executor        executor(resovle,reject)    }
  1. 每个promise都有一个状态可能为pending或resolved,rejected。而且初始状态都为pending。因此需要添加个status来表示当前promise的状态.。并且每个promise有自己的data。
function Promise(executor) {        var self = self        新增代码        self.status = 'pending' // 给promise对象指定status属性,初始值为pending            self.data = undefined // 给promise对象指定一个存储结果的data        function resovle() {        }        function reject() {        }        // 立即同步执行executor        executor(resovle,reject)    }

此外,当我们这样使用Promise的时候,

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

这时执行到then,因为我们传入的立即执行函数没有执行resolve或者reject,所以promise的状态还是pending,这时要把then里面的回调函数保存起来,所以需要个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)    }

那 then函数是怎么把传入的回调收集起来的。其实很简单,就是判断当前promise是否为pending状态,是的话,就把回调push到callbacks中。

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'){        }else{        }    }
  1. 在上面的例子1的基础上,当我们执行resovle(value)时,如例2
// 例2var promise = new Promise((resolve,reject)=>{    setTimeout(function () {        resolve(1)    })})promise.then(    value=>{console.log(value)},    err=>{console.log(err)}    )

此时代码执行情况是怎么样的呢?

  1. 先执行new Promise里的代码,然后发现个定时器,js线程将定时器交给定时器线程处理,2. 然后继续执行下面的代码,发现是then,而且当前的promise还是pending的状态。就把then里的回调函数放到callbacks中。
  2. 5秒后定时器线程将定时器里的回调函数(也就是宏任务)放到消息队列中,js线程在消息队列里发现了这个宏任务,就把它拿来执行。
  3. 执行这个宏任务,就执行了resolve(1),此时promise的callbacks里的回调被执行。并将当前promise状态改为resolved。然后这个1也会被保存到当前promise对象中

那怎么实现resolve呢?依旧上面的描述,就知道resovle的功能是执行callbacks里的函数,并保存data并将当前promise状态改为resolved。所以我们可以这么实现

function resolve(value) {    // 将状态改为resolved    self.status = 'resolved'    // 保存value的值    self.data = value    // 如果有待执行的callback函数,立即异步执行回调函数onResolved    if (self.callbacks.length>0){        self.callbacks.forEach(callbackObj=>{            callbackObj.onResolved(value)        })    }}
  1. 我们还知道,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=>{ A                callbackObj.onResolved(value)            })        })    }}
  1. 异曲同工之妙的是reject方法也是这个道理,因此这里无需赘述
function reject(value) {    // 如果当前状态不是pending,则不执行    if(self.status !== 'pending'){        return    }    // 将状态改为rejected    self.status = 'rejected'    // 保存value的值    self.data = value    // 如果有待执行的callback函数,立即异步执行回调函数onResolved    if (self.callbacks.length>0){      self.callbacks.forEach(callbackObj=>{          callbackObj.onRejected(value)      })    }}
  1. 我们又知道,当在执行executor的时候,如果执行异常的话,这个promise的状态会直接执行reject方法。例如
// 例 3var promise = new Promise((resolve,reject)=>{    error;执行到这里出错了    setTimeout(function () {        resolve(1)    })})

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

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

好了,现在测试下

 // 例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);        }    )

发现成功。 成功输出onResolved:1

3. 实现then方法

我们在上面简单的实现了当前promise为pending状态的情况,如:

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'){    }else{    }}

那其他情况呢?

执行到then时,promise可能会是pending状态,此时就要把then里的回调函数保存起来,也可能会是resolved或者rejected状态,此时就不用把回调保存起来,直接执行onResolved或onRejected方法。注意是异步执行。而且是做为微任务的,这里我们简单的用setTimeout来实现就好了。

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的时候,则执行then的时候,会执行第二个判断语句

则当前执行第二个判断语句的时候会出现三种情况

  1. 如果then里的回调函数返回的不是promise,return的新promise的状态是则是resolved,value就是返回的值。例如:
// 例5let promise = new Promise((resolve,reject)=>{    resolve(1)})promise.then(    value=>{        return value //返回的不是promise,是value    })

因此,我们可以这样实现

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)            })        }    })}

简单解释下:

执行onResolved(self.data),其实就是执行例子中的下面这个回调函数

value=>{        return value //返回的不是promise,是value    }

那么这个回调函数返回了value。就把value传入resolve函数,resolve函数将当前新的promise的状态改为resolved,同时将value保存到当前新的promise的data中。

  1. 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果,如代码所示,我们返回一个新的promise。如果这个promise执行了resolve,返回的新的promise的状态则是resolved的。否则为rejected
// 例6let promise = new Promise((resolve,reject)=>{    resolve(1)})promise.then(    value=>{        return new Promise((resolve,reject)=>{            resolve(2)            //或者            //reject(error)        })    })

因此我们可以这样实现

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里的

value=>{        return new Promise((resolve,reject)=>{            resolve(2)            //或者            //reject(error)        })    }

则返回一个promise对象,这个promise对象可能为resolved状态(执行 resolve(2))也可能为rejected状态(执行reject(error))。

将会导致value => {resolve(value)},这个回调函数的执行或者 reason => {reject(reason)}的执行。

因此会把即将返回的新的promise的data设置为value或者,reason。会把状态设置为resolved或者rejected。

  1. 如果执行这段代码的时候抛出错误,则返回的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会发生值传透,例如

let promsie = new Promise((resolve,reject)=>{    resolve(1)})promsie  .then(2)  .then(3)  .then(value =>console.log(value))

运行结果: 1

解释:.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。值传透可以理解为,当传入then的不是函数的时候,这个then是无效的。而实际原理上其实是当then中传入的不算函数,则这个then返回的promise的data,将会保存上一个的promise.data。这就是发生值穿透的原因。而且每一个无效的then所返回的promise的状态都为resolved

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

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

onResolved = typeof onResolved === 'function'? onResolved: value => valueonRejected = typeof onRejected === 'function'? onRejected: reason => {throw reason}

实际上就是改写,如果传入的不是函数,那就忽略那个传入值,自己再写一个函数。这个函数的执行结果将返回上一个promise的data

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方法可以传三种值

  1. 不是promise
  2. 成功状态的promise
  3. 失败状态的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)=>{                            })        })    }

有两种结果:

  1. 遍历到有一个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)                    }                )            })        })    }
  1. 遍历所有的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)                    }                )            })        })    }

本文转载于:https://juejin.cn/post/6856213486633304078如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。