• 手写 Promise


    就是干

    ECMAscript 6 原生提供了 Promise 对象。Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
    接下来用分块、分步骤、加注释来一步一步,实现手写 Promise。

    一、实现 Promise 的基本使用

    1. Promise 就是一个类在执行这个类的时候需要传递一个执行器进去,执行器会立即执行
    2. Promise 中有三种状态 分别为 等待(pending) 成功(fulfilled)失败(rejected)
      一旦状态确定就不可更改
      pending -> fulfilled
      pending -> rejected
    3. resolve 和 reject 函数是用来更改状态的
      resolve: fulfilled
      reject: rejected
    4. then 方法内部做的事情就判断状态,如果状态成功就调用成功的回调函数,如果状态失败就调用失败的回调函数 then 方法是被定义在原型对象上面
    5. 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 // 失败后的值
      // resolve,reject 箭头函数 是为了让这个函数内部 this 指向这个类的实例对象,也就是 promise
      resolve = (value) => {
        // 如果状态不是等待 阻止程序继续执行
        if (this.status !== PENDING) return
        // 将状态改为成功
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
      }
      reject = (reason) => {
        // 如果状态不是等待 阻止程序继续执行
        if (this.status !== PENDING) return
        // 将状态改为成功
        this.status = REJECTED
        // 保存失败后的原因
        this.reason = reason
      }
      then(successCallback, failCallback) {
        // 判断状态
        if (this.status === FULFILLED) {
          successCallback(this.value)
        } else if (this.status === REJECTED) {
          failCallback(this.reason)
        }
      }
    }
    

    二、实现 Promise 的异步情况

    1. 处理异步情况 和多个 promise.then 这里指的是多个 promise 的使用,并不是链式调用
    class MyPromise {
      constructor(executor) {
        executor(this.resolve, this.reject)
      }
      status = PENDING // 默认值 等待
      value = undefined // 成功之后的值
      reason = undefined // 失败后的值
      successCallback = [] // 成功回调,存储多个函数,链式调用
      failCallback = [] // 失败回调,存储多个函数,链式调用
      // resolve,reject 箭头函数 是为了让这个函数内部 this 指向这个类的实例对象,也就是 promise
      resolve = (value) => {
        // 如果状态不是等待 阻止程序继续执行
        if (this.status !== PENDING) return
        // 将状态改为成功
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
        // 循环存储的成功回调函数长度,然后依次执行
        while (this.successCallback.length) this.successCallback.shift()(this.value)
      }
      reject = (reason) => {
        // 如果状态不是等待 阻止程序继续执行
        if (this.status !== PENDING) return
        // 将状态改为成功
        this.status = REJECTED
        // 保存失败后的原因
        this.reason = reason
        // 循环存储的失败回调函数长度,然后依次执行
        while (this.failCallback.length) this.failCallback.shift()(this.reason)
      }
      then(successCallback, failCallback) {
        // 判断状态
        if (this.status === FULFILLED) {
          successCallback(this.value)
        } else if (this.status === REJECTED) {
          failCallback(this.reason)
        } else {
          // 因为等待期间你不知道后面执行的是成功的回调还是失败的回调
          // 所以将成功回调和失败回调存储起来
          this.successCallback.push(successCallback)
          this.failCallback.push(failCallback)
        }
      }
    }
    

    三、实现 Promise 的链式调用及捕获错误信息

    1. then 方法的链式调用,以及避免 promise 对象自已返回自己 形成循环
    2. 将 then 参数变成可选参数
    3. 捕获执行器错误信息,以及使用 then 时捕获错误信息
    class MyPromise {
      constructor(executor) {
        try {
          executor(this.resolve, this.reject)
        } catch (e) {
          this.reject(e)
        }
      }
      status = PENDING // 默认值 等待
      value = undefined // 成功之后的值
      reason = undefined // 失败后的值
      successCallback = [] // 成功回调,存储多个函数,链式调用
      failCallback = [] // 失败回调,存储多个函数,链式调用
      // resolve,reject 箭头函数 是为了让这个函数内部 this 指向这个类的实例对象,也就是 promise
      resolve = (value) => {
        // 如果状态不是等待 阻止程序继续执行
        if (this.status !== PENDING) return
        // 将状态改为成功
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
        // 循环存储的成功回调函数长度,然后依次执行
        while (this.successCallback.length) this.successCallback.shift()()
      }
      reject = (reason) => {
        // 如果状态不是等待 阻止程序继续执行
        if (this.status !== PENDING) return
        // 将状态改为成功
        this.status = REJECTED
        // 保存失败后的原因
        this.reason = reason
        // 循环存储的失败回调函数长度,然后依次执行
        while (this.failCallback.length) this.failCallback.shift()()
      }
      then(successCallback, failCallback) {
        // 判断,变成可选参数,假设第一个,第二个 .then 不传参数,第三个传参,一样能拿到数据 
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : reason => { throw reason }
        // 为了链式调用返回一个新的 promise 对象
        let newPromise = new MyPromise((resolve, reject) => {
          // 判断状态
          if (this.status === FULFILLED) {
            // 这里用计时器的原因是为了异步调用,因为需要等 newPromise 执行完毕后,才可以把他当参数传递给 resolvePromise 这个函数
            setTimeout(() => {
              try {
                let x = successCallback(this.value)
                // 存储上一个成功回调的返回值,传递给下一个 .then
                // 判断 x 的值是普通值还是 promise 对象
                // 如果是普通值,直接调用 resolve
                // 如果是 promise 对象,查看 promise 对象返回的结果
                // 再根据 promise 对象返回的结果,决定调用 resolve 还是 reject
                // 声明一个方法,进行操作
                resolvePromise(newPromise, x, resolve, reject)
              } catch (e) {
                reject(e)
              }
            }, 0)
          } else if (this.status === REJECTED) {
            setTimeout(() => {
              try {
                let x = failCallback(this.reason)
                // 存储上一个成功回调的返回值,传递给下一个 .then
                // 判断 x 的值是普通值还是 promise 对象
                // 如果是普通值,直接调用 resolve
                // 如果是 promise 对象,查看 promise 对象返回的结果
                // 再根据 promise 对象返回的结果,决定调用 resolve 还是 reject
                // 声明一个方法,进行操作
                resolvePromise(newPromise, x, resolve, reject)
              } catch (e) {
                reject(e)
              }
            }, 0)
          } else {
            // 因为等待期间你不知道后面执行的是成功的回调还是失败的回调
            // 所以将成功回调和失败回调存储起来
            this.successCallback.push(() => {
              setTimeout(() => {
                try {
                  let x = successCallback(this.value)
                  // 存储上一个成功回调的返回值,传递给下一个 .then
                  // 判断 x 的值是普通值还是 promise 对象
                  // 如果是普通值,直接调用 resolve
                  // 如果是 promise 对象,查看 promise 对象返回的结果
                  // 再根据 promise 对象返回的结果,决定调用 resolve 还是 reject
                  // 声明一个方法,进行操作
                  resolvePromise(newPromise, x, resolve, reject)
                } catch (e) {
                  reject(e)
                }
              }, 0)
            })
            this.failCallback.push(() => {
              setTimeout(() => {
                try {
                  let x = failCallback(this.reason)
                  // 存储上一个成功回调的返回值,传递给下一个 .then
                  // 判断 x 的值是普通值还是 promise 对象
                  // 如果是普通值,直接调用 resolve
                  // 如果是 promise 对象,查看 promise 对象返回的结果
                  // 再根据 promise 对象返回的结果,决定调用 resolve 还是 reject
                  // 声明一个方法,进行操作
                  resolvePromise(newPromise, x, resolve, reject)
                } catch (e) {
                  reject(e)
                }
              }, 0)
            })
          }
        })
        return newPromise
      }
    }
    function resolvePromise(newPromise, x, resolve, reject) {
      if (newPromise === x) {
        return reject(new TypeError('出错了大爷,不要自己调自己'))
      }
      if (x instanceof MyPromise) {
        // 判断是否是实例对象就行
        // 如果成功就调用 resolve,如果失败就调用 reject
        x.then(resolve, reject)
      } else {
        // 普通值
        resolve(x)
      }
    }
    

    四、实现 Promise.all()

    1. 实现 Promise.all()
    2. 实现 Promise.resolve()
    3. 实现 finally()
    因为下述代码只是新增了几个静态方法,剩余代码同第三步一是样的,所以只展示新增的变化
    class MyPromise {
      // 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++) {
            // 循环 all 数组里面的值
            let current = array[i]
            if (current instanceof MyPromise) {
              // promise 对象
              current.then(value => addData(i, value), reason => reject(reason))
            } else {
              // 普通值
              addData(i, array[i])
            }
          }
        })
      }
      // resolve
      static resolve (value) {
        if (value instanceof MyPromise) return value
        return new MyPromise ((resolve) => resolve(value))
      }
      // finally
      finally (callback) {
        return this.then((value) => {
          return MyPromise.resolve(callback()).then(() => value)
        }, (reason) => {
          return MyPromise.resolve(callback()).then(() => {throw reason})
        })
      }
      catch (failCallback) {
        return this.then(undefined, failCallback)
      }
    }
    

    结束 OVER

  • 相关阅读:
    AZ 305学习笔记
    Google Earth Engine(GEE)——多源遥感变量筛选(PCA主成分分析),变量筛选/降维处理
    linux云服务器病毒处理
    java毕业设计安全管理系统mybatis+源码+调试部署+系统+数据库+lw
    掌动智能:性能测试工具优势有哪些
    微信小程序连接阿里云快速入门【物联网】
    若依(RuoYi )权限管理设计
    fiddler抓包实践接口测试
    Methoxy-PEG-PCL,Methoxy-PEG-Poly(ε-caprolactone)可以作为制备纳米颗粒的重要原料
    【机器学习、python】线性回归
  • 原文地址:https://www.cnblogs.com/earthZhang/p/16291811.html