手写promise学习

89 阅读11分钟
记录Promise学习笔记

下面是模仿过程,我会根据我的理解记录下来

let promise = new Promise((resolve, reject) => {
  resolve('成功的 promise')
})
  1. 系统的Promise是一个类,所以我们应该创建一个类,Promise是立即执行的,所以我们应该在类里面立马执行这个执行器函数,所以写在constructor中,这个执行器接收两个参数函数,一个是成功的回调,一个是失败的回调,Promise有三种状态,同时then方法接收两个回调方法,一个成功的回调,一个是失败的回调,所以初次的框架应该是这样
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功的状态
const REJECTED = 'rejected' // 失败

class MyPromise {
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING // 状态
  value = undefined // 成功回调的值
  reason = undefined // 失败的原因
  // 箭头函数可以让这两函数this始终指向当前的promise
  resolve = (value) => {
  // 判断如果状态改变了,将不会往下执行
    if (this.status !== PENDING) return
    // 如果是reslove, 把它的状态置为成功
    this.status = FULFILLED
    // 成功的值
    this.value = value
  }
  reject = (reason) => {
  // 判断如果状态改变了,将不会往下执行
    if (this.status !== PENDING) return
    // 如果是reject, 把状态改为失败状态
    this.status = REJECTED
    // 失败的原因
    this.reason = reason
  }
  then(successCallBack, errorCallBack) {
    // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
    if (this.status === FULFILLED) {
      successCallBack(this.value)
    } else if(this.status === REJECTED) {
      errorCallBack(this.reason)
    }
  }
}

module.exports = MyPromise
}
let p1 = new MyPromise((resolve, reject) => {
  // resolve('成功')
  reject('失败')
})

p1.then(res => {
  console.log(res);
}, err=> {
  console.log(err);
})

可以看到resolve走的是then成功回调,reject走的是then失败的回调

那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,比如下面这种情况

let p1 = new MyPromise((resolve, reject) => {
  // resolve('成功')
  // reject('失败')
  setTimeout(() => {
    resolve('成功')
  }, 2000)
})

我们知道setTimeout是个异步代码,那么在还没执行到resolve改变状态就执行到then了,所以在这个时候,状态应该是PENDING,并把then的回调函数保存起来,等resolve执行在把then里面的函数执行

const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功的状态
const REJECTED = 'rejected' // 失败

class MyPromise {
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING // 状态
  value = undefined // 成功回调的值
  reason = undefined // 失败的原因
  // 新增这两行
  successCallBack = []
  errorCallBack = []
  // 箭头函数可以让这两函数this始终指向当前的promise
  resolve = (value) => {
    // 如果是reslove, 把它的状态置为成功
    this.status = FULFILLED
    // 成功的值
    this.value = value
    // 如果是异步的情况下(新增)
    while(this.successCallBack.length) this.successCallBack.shift()(this.value)
  }
  reject = (reason) => {
    // 如果是reject, 把状态改为失败状态
    this.status = REJECTED
    // 失败的原因
    this.reason = reason
    // 如果是异步的情况下(新增)
    while(this.errorCallBack.length) this.errorCallBack.shift()(this.reason)
  }
  then(successCallBack, errorCallBack) {
    // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
    if (this.status === FULFILLED) {
      successCallBack(this.value)
    } else if(this.status === REJECTED) {
      errorCallBack(this.reason)
    } else {
      // 新增
      // 那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,那么我们可以把回调存起来,等到执行resolve的时候,再执行回调
      this.successCallBack.push(successCallBack)
      this.errorCallBack.push(errorCallBack)
    }
  }
}

module.exports = MyPromise
处理返回值

因为then是可以继续链式调用下去的,所以then函数返回的是一个promise对象

// 其他代码省略。。。。
then(successCallBack, errorCallBack) {
    // then函数会返回一个promise
    let promise2 = new MyPromise((resolve, reject) => {
       // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
      if (this.status === FULFILLED) {
        let x = successCallBack(this.value)
        resolve(x)
      } else if(this.status === REJECTED) {
        errorCallBack(this.reason)
      } else {
        // 那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,那么我们可以把回调存起来,等到执行resolve的时候,再执行回调
        this.successCallBack.push(successCallBack)
        this.errorCallBack.push(errorCallBack)
      }
    })
    return promise2
  }

上述的代码只是能满足返回普通值的情况下,如果返回的是promise,那么还得处理一下

声明一个函数,用来判断返回值是普通值还是promise对象

function resolvePromise(x, resolve, reject) {
  // 如果返回值是promise
  if (x instanceof MyPromise) {
    // 就把这个promise对象的值拿到,resolve给下一个then
    // x.then(value => resolve(value), reason => reject(reason)),用替换法则就知道为啥要简写成这样了
    // 上面代码的简写
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}
  then(successCallBack, errorCallBack) {
    // then函数会返回一个promise
    let promise2 = new MyPromise((resolve, reject) => {
       // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
      if (this.status === FULFILLED) {
        let x = successCallBack(this.value)
        // 新增
        resolvePromise(x, resolve, reject)
        // resolve(x)
      } else if(this.status === REJECTED) {
        errorCallBack(this.reason)
      } else {
        // 那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,那么我们可以把回调存起来,等到执行resolve的时候,再执行回调
        this.successCallBack.push(successCallBack)
        this.errorCallBack.push(errorCallBack)
      }
    })
    return promise2
  }

到此,then的成功回调处理返回值已经处理完了,剩下的失败跟等待的同样

resolve = (value) => {
    // 如果是reslove, 把它的状态置为成功
    this.status = FULFILLED
    // 成功的值
    this.value = value
    // 如果是异步的情况下
    while(this.successCallBack.length) this.successCallBack.shift()() // 注意这里没参数了
  }
  reject = (reason) => {
    // 如果是reject, 把状态改为失败状态
    this.status = REJECTED
    // 失败的原因
    this.reason = reason
    // 如果是异步的情况下
    while(this.errorCallBack.length) this.errorCallBack.shift()() // 注意这里没参数了
  }
//省略。。。。。
then(successCallBack, errorCallBack) {
    // then函数会返回一个promise
    let promise2 = new MyPromise((resolve, reject) => {
       // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
      if (this.status === FULFILLED) {
        let x = successCallBack(this.value)
        resolvePromise(x, resolve, reject)
        // resolve(x)
      } else if(this.status === REJECTED) {
        let x = errorCallBack(this.reason)
        resolvePromise(x, resolve, reject)
      } else {
        // 那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,那么我们可以把回调存起来,等到执行resolve的时候,再执行回调
        this.successCallBack.push(() => {
          let x = successCallBack(this.value)
          resolvePromise(x, resolve, reject)
        })
        this.errorCallBack.push(() => {
          let x = errorCallBack(this.reason)
          resolvePromise(x, resolve, reject)
        })
      }
    })
    return promise2
  }

上面的代码可以返回promise跟普通值了

处理捕获

Promise是可以捕获到异常的,所以我们也给我们的promise加上捕获代码

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e.message)
    }
  }
}
// 省略..........
 then(successCallBack, errorCallBack) {
    // then函数会返回一个promise
    let promise2 = new MyPromise((resolve, reject) => {
       // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
      if (this.status === FULFILLED) {
        try {
          let x = successCallBack(this.value)
          resolvePromise(x, resolve, reject)
        } catch (e) {
          reject(e)
        }
        // resolve(x)
      } else if(this.status === REJECTED) {
        try {
          let x = errorCallBack(this.reason)
          resolvePromise(x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      } else {
        // 那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,那么我们可以把回调存起来,等到执行resolve的时候,再执行回调
        this.successCallBack.push(() => {
          try {
            let x = successCallBack(this.value)
            resolvePromise(x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
        this.errorCallBack.push(() => {
          try {
            let x = errorCallBack(this.reason)
            resolvePromise(x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
    })
    return promise2
  }
let p1 = new MyPromise((resolve, reject) => {
  // throw new Error('executor')
  // resolve('P1成功')
  reject('失败')
  // setTimeout(() => {
  //   reject('失败')
  // }, 2000)
})


p1.then(res => {
  console.log(res);
}, err => {
  throw new Error('then 抛出异常')
}).then(res => {
  console.log(res);
}, err => {
  console.log(err, '0000000');
})
then方法变为可选参数

如果then方法中没有传递参数,那么我们可以帮它造一个

 then(successCallBack, errorCallBack) {
    successCallBack = successCallBack ? successCallBack: value => value
    errorCallBack = errorCallBack ? errorCallBack : reason => { throw reason }
    // 省略.........
  }
let p1 = new MyPromise((resolve, reject) => {
  // throw new Error('executor')
  // resolve('P1成功')
  reject('失败')
  // setTimeout(() => {
  //   reject('失败')
  // }, 2000)
})

p1.then().then().then(res => {console.log(res)}, err=> {console.log(err)})
判断是否循环调用同一个promise
 then(successCallBack, errorCallBack) {
    successCallBack = successCallBack ? successCallBack: value => value
    errorCallBack = errorCallBack ? errorCallBack : reason => { throw reason }
    // then函数会返回一个promise
    let promise2 = new MyPromise((resolve, reject) => {
       // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
      if (this.status === FULFILLED) {
         // 因为这里需要拿到promise2, 所以把它变成异步代码
        setTimeout(() => {
          try {
            let x = successCallBack(this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
        // resolve(x)
      } else if(this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = errorCallBack(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else {
        // 那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,那么我们可以把回调存起来,等到执行resolve的时候,再执行回调
        this.successCallBack.push(() => {
          setTimeout(() => {
            try {
              let x = successCallBack(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        this.errorCallBack.push(() => {
          setTimeout(() => {
            try {
              let x = errorCallBack(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
      }
    })
    return promise2
  }
let p1 = new MyPromise((resolve, reject) => {
  // throw new Error('executor')
  resolve('P1成功')
  // reject('失败')
  // setTimeout(() => {
  //   reject('失败')
  // }, 2000)
})
let p = p1.then(res=> {
  console.log(res);
  return p
}, err=> {
  console.log(err);
})

p.then(res => {
  console.log(res);
  return p
}, err=> {
  console.log(err);
})
all方法

因为all是直接由Promise类直接调用的,所以是静态方法

    // all方法
  static all(array) {
    let result = []
    return new MyPromise((resolve, reject) => {
      for(let i = 0; i < array.length; i++) {
        let currData = array[i]
        if (currData instanceof MyPromise) {
          currData.then(value => result[i] = value, reason => {
            console.log(11);
            reject(reason)
          })
        } else {
          result[i] = currData
        }
      }
      console.log(22);
      resolve(result)
    })
  }

但是上面的代码还有点问题的,reject的时候返回的结果还是不对,因为这个时候状态总是fulfilled,then里面是异步代码,所以resolve先执行,一旦状态改变了就不会在改变了

let p1 = new MyPromise((resolve, reject) => {
  // throw new Error('executor')
  //resolve('P1成功')
  reject('失败')
  // setTimeout(() => {
  //   resolve('P1成功')
  // }, 2000)
})

let p2 = new MyPromise((resolve, reject) => {
  resolve('p2成功')
})


MyPromise.all(['a', 'b', p1, p2, 'c']).then(res => {console.log(res, '成功的回调')}, err => {console.log(err, '失败的回调')})

如果是异步代码的时候结果也不对

let p1 = new MyPromise((resolve, reject) => {
  // throw new Error('executor')
  // resolve('P1成功')
  // reject('失败')
  setTimeout(() => {
    resolve('P1成功')
  }, 2000)
})

let p2 = new MyPromise((resolve, reject) => {
  resolve('p2成功')
})


MyPromise.all(['a', 'b', p1, p2, 'c']).then(res => {console.log(res, '成功的回调')}, err => {console.log(err, '失败的回调')})

image.png 我们得等到所有结果返回后再返回resolve

 // all方法
  static all(array) {
    let result = []
    let index = 0
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        result[key] = value
        index++
        if (index === array.length) {
          resolve(result)
        }
      }
      for(let i = 0; i < array.length; i++) {
        let currData = array[i]
        if (currData instanceof MyPromise) {
          currData.then(value => addData(i, value), reason => reject(reason))
        } else {
          addData(i, currData)
        }
      }
      console.log(22);
    })
  }
resolve方法

resolve方法能调用then方法,证明resolve返回的是promise

  // resolve方法
  static resolve(value) {
    // 如果是promise,直接返回promise
    if (value instanceof MyPromise) return value
    // 否则返回一个promise
    return new MyPromise((resolve, reject) => {
      resolve(value)
    })
  }
}
let p2 = new MyPromise((resolve, reject) => {
  resolve('p2成功')
})


MyPromise.resolve(p2).then(res => {console.log(res)})
catch方法跟reject方法
catch(callback) {
   return this.then(undefined, callback)
}
// reject方法
static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
}
let p2 = new MyPromise((resolve, reject) => {
  // resolve('p2成功')
  reject('失败')
})

p2.catch(e => {
  console.log(e,'000');
  return p1
}).then(res=> {
  console.log(res);
}, err => {
  console.log(err);
})
finally方法
  1. 不管是成功还是失败,都会调用finally方法一次
  2. 可以链式调用then方法,获取当前promise对象最终返回的结果
 finally(callback) {
    // 不管成功还是失败都会执行,then方法能拿到状态
    return this.then((value) => {
      callback()
      return value
    }, (reason) => {
      callback()
      return reason
    })
  }
let p2 = new MyPromise((resolve, reject) => {
  resolve('p2成功')
  // reject('失败')
})
p2.finally(() => {
  console.log('finally');
}).then((data=> {console.log(data)}, err => {console.log(err)}))

以上代码确实可以满足需求,但是finally也可以返回promise对象的,如果存在异步的情况下,后面的.then不会等到p1执行完才执行

let p1 = new MyPromise((resolve, reject) => {
  // throw new Error('executor')
  // resolve('P1成功')
  // reject('失败')
  setTimeout(() => {
    resolve('P1成功')
  }, 2000)
})

let p2 = new MyPromise((resolve, reject) => {
  resolve('p2成功')
  // reject('失败')
})

p2.finally(() => {
  console.log('finally');
  return p1
}).then((data=> {console.log(data)}, err => {console.log(err)}))

我们需要等到p1执行完后才开始执行后面的then

  finally(callback) {
    // 不管成功还是失败都会执行,then方法能拿到状态
    return this.then((value) => {
      // 不管是不是promise,都转成promise
      return MyPromise.resolve(callback()).then(() => value)
    }, (reason) => {
      return MyPromise.resolve(callback()).then(() => {throw reason})
    })
  }

完整代码


const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功的状态
const REJECTED = 'rejected' // 失败

class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e.message)
    }
  }
  status = PENDING // 状态
  value = undefined // 成功回调的值
  reason = undefined // 失败的原因
  successCallBack = []
  errorCallBack = []
  // 箭头函数可以让这两函数this始终指向当前的promise
  resolve = (value) => {
    // 判断如果状态改变了,将不会往下执行
    if (this.status !== PENDING) return
    // 如果是reslove, 把它的状态置为成功
    this.status = FULFILLED
    // 成功的值
    this.value = value
    // 如果是异步的情况下
    while(this.successCallBack.length) this.successCallBack.shift()()
  }
  reject = (reason) => {
    // 判断如果状态改变了,将不会往下执行
    if (this.status !== PENDING) return
    // 如果是reject, 把状态改为失败状态
    this.status = REJECTED
    // 失败的原因
    this.reason = reason
    // 如果是异步的情况下
    while(this.errorCallBack.length) this.errorCallBack.shift()()
  }
  then(successCallBack, errorCallBack) {
    successCallBack = successCallBack ? successCallBack: value => value
    errorCallBack = errorCallBack ? errorCallBack : reason => { throw reason }
    // then函数会返回一个promise
    let promise2 = new MyPromise((resolve, reject) => {
       // 判断状态如果是成功就调用successCallBack的回调,失败的状态就调用errorCallBack
      if (this.status === FULFILLED) {
         // 因为这里需要拿到promise2, 所以把它变成异步代码
        setTimeout(() => {
          try {
            let x = successCallBack(this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
        // resolve(x)
      } else if(this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = errorCallBack(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        }, 0)
      } else {
        // 那我们现在可以考虑下,如果是异步情况下,then代码要怎么执行,那么我们可以把回调存起来,等到执行resolve的时候,再执行回调
        this.successCallBack.push(() => {
          setTimeout(() => {
            try {
              let x = successCallBack(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
        this.errorCallBack.push(() => {
          setTimeout(() => {
            try {
              let x = errorCallBack(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          }, 0)
        })
      }
    })
    return promise2
  }
  catch(callback) {
    return this.then(undefined, callback)
  }
  // finally
  finally(callback) {
    // 不管成功还是失败都会执行,then方法能拿到状态
    return this.then((value) => {
      // 不管是不是promise,都转成promise
      return MyPromise.resolve(callback()).then(() => value)
    }, (reason) => {
      return MyPromise.resolve(callback()).then(() => {throw reason})
    })
  }
  // all方法
  static all(array) {
    let result = []
    let index = 0
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        result[key] = value
        index++
        if (index === array.length) {
          resolve(result)
        }
      }
      for(let i = 0; i < array.length; i++) {
        let currData = array[i]
        if (currData instanceof MyPromise) {
          currData.then(value => {
            console.log(i,value);
            addData(i, value)
          }, reason => reject(reason))
        } else {
          console.log(i,currData);
          addData(i, currData)
        }
      }
      console.log(22);
    })
  }
  // resolve方法
  static resolve(value) {
    // 如果是promise,直接返回promise
    if (value instanceof MyPromise) return value
    // 否则返回一个promise
    return new MyPromise((resolve, reject) => {
      resolve(value)
    })
  }
  // reject方法
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  // 判断是否是同一个promise
  if (x === promise2) return reject(new TypeError('Uncaught (in promise) TypeError: Chaining cycle detected for promise #<Promise>'))
  // 如果返回值是promise
  if (x instanceof MyPromise) {
    // 就把这个promise对象的值拿到,resolve给下一个then
    // x.then(value => resolve(value), reason => reject(reason)),用替换法则就知道为啥要简写成这样了
    // 上面代码的简写
    x.then(resolve, reject)
  } else {
    resolve(x)
  }
}

module.exports = MyPromise