Promise原理分析、手写Promise简易版

634 阅读4分钟

一、前言

Promise灵魂三问:是什么?做什么?怎么做?

  1. 是什么?----Promise 是异步编程的一种解决方案,ES6新增的一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。

  2. 做什么?----Promise 解决回调地狱的问题,在多层嵌套的回调方法中,如果同时存在同步、异步的方法,那么实际执行顺序会混乱,不好调试不好维护。

  3. 怎么做?
    3.1 假设有一个需求,对接服务端接口时,想要拿到接口url 为 'url5' 返回的data5,但是url5需要根据url4返回的数据作为参数,url4又需要url3返回的数据作为参数,以此类推 ······(嵌套层级略微夸张了一点点,但实际开发中经常出现类似这种依赖上一个接口返回的数据作为下一个接口的传递参数)

    不使用Promise处理方案:

        $.get('/url1', function (data1) {
          $.get('/url2', data1, function (data2) {
            $.get('/url3', data2, function (data3) {
              $.get('/url4', data3, function (data4) {
                $.get('/url5', data4, function (data5) {
                    console.log(data5) 
                  })
              })
            })
          })
        })
    

    使用Promise处理方案:

    let promise = new Promise((resolve, reject) => {
      $.get('/url1', data1 => {
        resolve(data1)
      })
    })
    
    promise.then((data1) => {
      $.get('/url2', data1, data2 => {
        return data2
      })
    }).then((data2) => {
      $.get('/url3', data2, data3 => {
        return data3
      })
    }).then((data3) => {
      $.get('/url4', data3, data4 => {
        console.log(data4)
      })
    })
    
    

二、Promise使用原理分析

  1. Promise 就是一个类,在执行这个类的时候,需要传递一个执行器进去,执行器会立即执行
  2. Promise 中有三种状态,分别为 等待pending, 成功 fulfilled ,失败 rejected
    pending -> fulfilled
    pending -> rejected
    状态一旦确定就不可更改
  3. resolvereject函数是用来更改状态的
    resolvefulfilled
    rejectrejected
  4. then方法内部做的事情就判断状态 如果状态是成功就调用成功的回调函数 如果状态是失败,就调用失败的回调函数
    then方法是定义在原型对象当中
  5. then成功回调有一个参数 表示成功之后的值 then失败回调用一个参数,表示失败后的原因

三、手写Pormise

  1. 创建Mypromise.js文件,根据上述1. 2. 3. 原理分析,我们定义三种状态,创建一个MyPromise的类,执行器立即执行,初始化状态为PENDING,定义resolvereject 方法,代码如下:
    const PENDING = "pending" //等待
    const FULFILLED = "fulfilled" //成功
    const REJECT = "reject" //失败
    
    class MyPromise {
      constructor(executor) {
        executor(this.resolve, this.reject)
      }
      // 初始状态  等待
      status = PENDING

      resolve = () => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED
      }
      reject = () => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECT
      }
    }
  1. 根据上诉4. 5.原理分析,我们需要定义then方法,主要是判断当前状态调用成功或者失败的函数,需要提前声明successCallbackfailCallback分别为成功和失败的回调函数,回调函数中需要传递成功的值value或者传递错误信息reason,因此valuereason需要提前声明,代码如下:
    // 声明成功返回的初始值
    value = undefined
    // 声明失败返回的原因
    reason = undefined
    // 声明成功回调函数
    successCallback = undefined
    // 声明失败回调函数
    failCallback = undefined
    then (successCallback, failCallback) {
        if (this.status === FULFILLED) {
          successCallback(this.value)
        } else if (this.status === REJECT) {
          failCallback(this.reason)
        }
    }

因为我们then方法中successCallbackfailCallback回调函数中需要用上valuereason的值作为参数传递,所以我们应该在resolvereject中分别保存接受到的valuereason,代码修改如下:

    resolve = value => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED
        // 保存成功之后的值,传递给then方法
        this.value = value
        }
        reject = reason => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECT
        // 保存失败之后的原因,传递给then方法
        this.reason = reason
    }

此时,基础简易版已经完成,需要module.exports = MyPromise导出

四、最终代码和使用

MyPromise.js

    const PENDING = "pending" //等待
    const FULFILLED = "fulfilled" //成功
    const REJECT = "reject" //失败

    class MyPromise {
      constructor(executor) {
        executor(this.resolve, this.reject)
      }
      // 初始状态  等待
      status = PENDING
      // 声明成功返回的初始值
      value = undefined
      // 声明失败返回的原因
      reason = undefined
      // 声明成功回调函数
      successCallback = undefined
      // 声明失败回调函数
      failCallback = undefined
      resolve = value => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为成功
        this.status = FULFILLED
        // 保存成功之后的值,传递给then方法
        this.value = value
      }
      reject = reason => {
        // 如果状态不是等待 阻止程序向下执行
        if (this.status !== PENDING) return
        // 将状态更改为失败
        this.status = REJECT
        // 保存失败之后的原因,传递给then方法
        this.reason = reason
      }
      then (successCallback, failCallback) {
        if (this.status === FULFILLED) {
          successCallback(this.value)
        } else if (this.status === REJECT) {
          failCallback(this.reason)
        }
      }
    }

    module.exports = MyPromise

创建index.js导入我们的Pormise类并使用它,代码如下:

    const MyPromise = require('./MyPromise')

    let promise = new MyPromise((resolve, reject) => {
      resolve('成功值')
      // reject('失败信息')
    })
    promise.then(value => {
      console.log(value) // 成功值
    }, reason => {
      console.log(reason) // 失败信息
    })

在控制台中输入node index.js启动