Promise原理

作者: 没名字的某某人 | 来源:发表于2022-01-20 14:15 被阅读0次

写在最前,本文转自掘金

resolve和reject

这里有四个知识点

  • 执行了resolve,Promise状态会变成fulfilled
  • 执行了reject,Promise状态会变成rejected
  • Promise只以第一次为准,状态改变就永久改变
  • Promise中有throw的话,就相当于执行了reject
    那么咱们就把这四个知识点一步步实现吧

1. 实现resolve与reject

注意,Promise的初始状态是pending
这里很重要的一步是resolve和reject的绑定this,为什么要绑定this呢,这是为了this永远指向当前MyPromise实例,防止随着函数执行环境的改变而改变

class MyPromise{
      constructor(executor){
        // 初始化值
        this.initValue()
        // 初始化this指向
        this.initBind()
        // 执行传进来的函数
        executor(this.resolve, this.reject)
      }
      initBind(){
        // 在不同的作用域下调用处理函数,会让处理函数中的this失去方向
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
      }
      initValue(){
        this.PromiseResult = null  // 终值
        this.PromiseState = 'pending'  // 状态
      }
      resolve(value){
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
      }
      reject(reason){
        // 与resolve同理
        this.PromiseState = 'rejected'
        this.PromiseResult = reason
      }
    }

咱们来测试一下吧

const test1 = new MyPromise((resolve, reject) => {
    resolve('成功')
})
console.log(test1) // MyPromise { PromiseState: 'fulfilled', PromiseResult: '成功' }

const test2 = new MyPromise((resolve, reject) => {
    reject('失败')
})
console.log(test2) // MyPromise { PromiseState: 'rejected', PromiseResult: '失败' }

2. 状态不可变

上面代码还未做到状态永久不变,其实只需要判断PromiseState是否改变就可以了

    resolve(value) {
        // state是不可变的
+        if (this.PromiseState !== 'pending') return
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
    }

    reject(reason) {
        // state是不可变的
+        if (this.PromiseState !== 'pending') return
        // 如果执行reject,状态变为rejected
        this.PromiseState = 'rejected'
        // 终值为传进来的reason
        this.PromiseResult = reason
    }

3. throw

Promise中有throw的话,相当于执行了reject。这就要使用try catch

+        try {
            // 执行传进来的函数
            executor(this.resolve, this.reject)
+        } catch (e) {
            // 捕捉到错误直接执行reject
+            this.reject(e)
+        }

then

这有四个知识点

  • then接收两个回调,一个是成功回调,一个是失败回调
  • 当Promise状态为fulfilled执行成功回调,为rejected执行失败回调
  • resolvereject在定时器里,则定时器结束后再执行then
  • then支持链式调用,下次then执行受上一次then返回值的影响

1. 实现then

then(onFulfilled, onRejected){
  // 接收两个回调,参数校验,确保一定是函数
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
  onRejected = typeof onRejected === 'function' ? onRejected: reason => {  throw reason }

  if(this.PromiseState === 'fulfilled'){
    // 如果当前为成功状态,执行第一个回调
    onFulfilled(this.PromiseResult)
  } else if(this.PromiseState === 'rejected'){
    onRejected(this.PromiseResult)
  }
}

2. 定时器情况

上面我们已经实现了then的基本功能,那如果是定时器情况呢?
如何才能保证1秒后才执行then里的回调函数呢?

我们不能保证1秒后才执行then函数,但是我们可以保证1秒后再执行then里的回调


watermark1.jpg

我们只需要在执行了resolve或reject函数后再调用之前存起来的回调函数,我们用数组来保存回调,因为一个promise实例可能会多次then,用数组就一个一个保存了

    initValue() {
        // 初始化值
        this.PromiseResult = null // 终值
        this.PromiseState = 'pending' // 状态
+        this.onFulfilledCallbacks = [] // 保存成功回调
+        this.onRejectedCallbacks = [] // 保存失败回调
    }

    resolve(value) {
        // state是不可变的
        if (this.PromiseState !== 'pending') return
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
        // 执行保存的成功回调
+        while (this.onFulfilledCallbacks.length) {
+            this.onFulfilledCallbacks.shift()(this.PromiseResult)
+        }
    }

    reject(reason) {
        // state是不可变的
        if (this.PromiseState !== 'pending') return
        // 如果执行reject,状态变为rejected
        this.PromiseState = 'rejected'
        // 终值为传进来的reason
        this.PromiseResult = reason
        // 执行保存的失败回调
+        while (this.onRejectedCallbacks.length) {
+            this.onRejectedCallbacks.shift()(this.PromiseResult)
+        }
    }
    
    then(onFulfilled, onRejected) {
        // 接收两个回调 onFulfilled, onRejected

        // 参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

        if (this.PromiseState === 'fulfilled') {
            // 如果当前为成功状态,执行第一个回调
            onFulfilled(this.PromiseResult)
        } else if (this.PromiseState === 'rejected') {
            // 如果当前为失败状态,执行第二哥回调
            onRejected(this.PromiseResult)
+        } else if (this.PromiseState === 'pending') {
+            // 如果状态为待定状态,暂时保存两个回调
+            this.onFulfilledCallbacks.push(onFulfilled.bind(this))
+            this.onRejectedCallbacks.push(onRejected.bind(this))
+        }

    }

3. 链式调用

then支持链式调用,下一次then执行受上一次then返回值的影响,给大家举个例子:

// 链式调用 输出 200
const p3 = new Promise((resolve, reject) => {
    resolve(100)
}).then(res => 2 * res, err => console.log(err))
    .then(res => console.log(res), err => console.log(err))

// 链式调用 输出300
const p4 = new Promise((resolve, reject) => {
    resolve(100)
}).then(res => new Promise((resolve, reject) => resolve(3 * res)), err => console.log(err))
    .then(res => console.log(res), err => console.log(err))

从上方例子,我们可以获取到几个知识点:

    1. then方法本身会返回一个新的Promise
    1. 如果返回值是promise对象,返回值为成功,新promise就是成功
    1. 如果返回值是promise对象,返回值为失败,新promise就是失败
    1. 如果返回值非promise对象,新promise对象就是成功,值为此返回值

咱们知道then是Promise上的方法,那如何实现then完还能再then呢?很简单,then执行返回一个Promise对象就行了,就能保证then完还能继续执行then


watermark2.jpg

代码实现

    then(onFulfilled, onRejected) {
        // 接收两个回调 onFulfilled, onRejected

        // 参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }


        var thenPromise = new MyPromise((resolve, reject) => {

            const resolvePromise = cb => {
                try {
                    const x = cb(this.PromiseResult)
                    if (x === thenPromise) {
                        // 不能返回自身哦
                        throw new Error('不能返回自身。。。')
                    }
                    if (x instanceof MyPromise) {
                        // 如果返回值是Promise
                        // 如果返回值是promise对象,返回值为成功,新promise就是成功
                        // 如果返回值是promise对象,返回值为失败,新promise就是失败
                        // 谁知道返回的promise是失败成功?只有then知道
                        x.then(resolve, reject)
                    } else {
                        // 非Promise就直接成功
                        resolve(x)
                    }
                } catch (err) {
                    // 处理报错
                    reject(err)
                    throw new Error(err)
                }
            }

            if (this.PromiseState === 'fulfilled') {
                // 如果当前为成功状态,执行第一个回调
                resolvePromise(onFulfilled)
            } else if (this.PromiseState === 'rejected') {
                // 如果当前为失败状态,执行第二个回调
                resolvePromise(onRejected)
            } else if (this.PromiseState === 'pending') {
                // 如果状态为待定状态,暂时保存两个回调
                // 如果状态为待定状态,暂时保存两个回调
                this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
                this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected))
            }
        })

        // 返回这个包装的Promise
        return thenPromise

    }

4. 微任务

then方法是微任务,所以我们需要让resolvePromise函数异步执行

 const resolvePromise = cb => {
    setTimeout(() => {
        try {
            const x = cb(this.PromiseResult)
            if (x === thenPromise) {
                // 不能返回自身哦
                throw new Error('不能返回自身。。。')
            }
            if (x instanceof MyPromise) {
                // 如果返回值是Promise
                // 如果返回值是promise对象,返回值为成功,新promise就是成功
                // 如果返回值是promise对象,返回值为失败,新promise就是失败
                // 谁知道返回的promise是失败成功?只有then知道
                x.then(resolve, reject)
            } else {
                // 非Promise就直接成功
                resolve(x)
            }
        } catch (err) {
            // 处理报错
            reject(err)
            throw new Error(err)
        }
    })
}

其它方法

all

  • 接受一个promise数组,数组中如有非promise项,则此项当做成功
  • 如果所有promise都成功,则反悔成功结果数组
  • 如果有一个promise失败,则返回这个失败结果
static all(promises) {
        const result = [] // 保存成功值 的数组
        let count = 0 // 判断是否调用完成
        return new MyPromise((resolve, reject) => {
          // 用于将成功回调添加进数组
          const addData = (index, value) => {
            result[index] = value // 收集 成功值
            count++ // 同时计算成功值个数
            if (count === promise.length) resolve(result) // 收集满了就执行resolve回调
          }
          // 循环获取promise
          promises.forEach((promise, idx) => {
            // 判断数组中是否有非Promise项
            if (promise instanceof MyPromise) {
              promise.then(res => {
                // 将成功回调里的数据添加到 数组中
                addData(idx, res)
              }, err => {
                reject(err) // 如果有一个错误,就执行 reject回调
              })
            } else {
              //  非promise项当做成功 添加到数组中
              addData(idx, promise)
            }
          })
        })
      }

race

  • 接受一个Promise数组,数组中如有非Promise项,则此项当做成功
  • 哪个Promise最快得到结果,就返回那个结果,无论成功失败
static race(promises){
        return new MyPromise((resolve, reject)=>{
          promises.forEach(promise=>{
            if(promise instanceof MyPromise){
              promise.then(res=>resolve(res),err=>reject(err))
            }else{
              resolve(promise)
            }
          })
        })
      }

allSettled

  • 接受一个Promise数组,数组中如有非promise项,则当此项成功
  • 把每个promise的结果,集合成数组返回
static allSettled(promises) {
        const res = [] // 保存成功值 的数组
        let count = 0 // 判断是否调用完成
        return new MyPromise((resolve, reject) => {
          // 用于将成功回调添加进数组
          const addData = (status, value, index) => {
            res[index] = {
              status,
              value
            } // 收集 成功值
            count++ // 同时计算成功值个数
            if (count === promise.length) resolve(res) // 收集满了就执行resolve回调
          }
          // 循环获取promise
          promises.forEach((promise, idx) => {
            // 判断数组中是否有非Promise项
            if (promise instanceof MyPromise) {
              promise.then(res => {
                // 将成功回调里的数据添加到 数组中
                addData('fulfilled', res, idx)
              }, err => {
                addData('rejected', err, idx)
              })
            } else {
              //  非promise项当做成功 添加到数组中
              addData('fulfilled', promise, idx)
            }
          })
        })
      }

any

any与all相反

  • 接受一个promise数组,数组中如有非promise项,则此项当做成功
  • 如果有一个promise成功,则返回这个成功结果
  • 如果所有promise都失败,则报错
static any(promises){
        let count = 0
        return new MyPromise((resolve,reject)=>{
          promises.forEach((promise)=>{
            promise.then(val=>{
              resolve(val)
            },err=>{
              count++
              if(count === promises.length){
                reject(new AggregateError('All promises were rejected'))
              }
            })
          })
        }) 
      }

最终代码

class MyPromise {
      constructor(executor) {
        // 初始化值
        this.initValue()
        // 初始化this指向
        this.initBind()
        try {
          // 执行传进来的函数
          executor(this.resolve, this.reject)
        } catch (e) {
          // 捕捉到错误直接执行reject
          this.reject(e)
        }

      }
      initBind() {
        // 在不同的作用域下调用处理函数,会让处理函数中的this失去方向
        this.resolve = this.resolve.bind(this)
        this.reject = this.reject.bind(this)
      }
      initValue() {
        this.PromiseResult = null // 终值
        this.PromiseState = 'pending' // 状态
        this.onFulfilledCallbacks = [] // 保存成功回调
        this.onRejectedCallbacks = [] // 保存失败回调
      }
      resolve(value) {
        // state是不可变的
        if (this.PromiseState != 'pending') return
        // 如果执行resolve,状态变为fulfilled
        this.PromiseState = 'fulfilled'
        // 终值为传进来的值
        this.PromiseResult = value
        // 执行保存的成功回调
        while (this.onFulfilledCallbacks.length) {
          this.onFulfilledCallbacks.shift()(this.PromiseResult)
        }
      }
      reject(reason) {
        // state是不可变的
        if (this.PromiseState != 'pending') return
        // 与resolve同理
        this.PromiseState = 'rejected'
        this.PromiseResult = reason
        // 执行保存的失败回调
        while (this.onRejectedCallbacks.length) {
          this.onRejectedCallbacks.shift()(this.PromiseResult)
        }
      }
      then(onFulfilled, onRejected) {
        // 接收两个回调,参数校验,确保一定是函数
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
        onRejected = typeof onRejected === 'function' ? onRejected : reason => {
          throw reason
        }
        // 作为下一次返回的promise
        let thenPromise = new MyPromise((resolve, reject) => {

          const resolvePromise = cb => {
            // 异步去执行回调函数
            setTimeout(() => {
              try {
                const x = cb(this.PromiseState) // then中回调函数执行结果
                // 回调函数执行的返回结果,不能是当前promise实例,因为这样永远都不会成功或者失败,所以应抛出一个错误
                if (x === thenPromise) {
                  throw new Error('不能返回自身')
                }
                // 如果回调函数执行的返回结果是promise,那么应该取出promise的结果,作为promise2成功或者失败结果
                if (x instanceof MyPromise) {
                  // 再次循环,获取promise2的结果
                  x.then(resolve, reject)
                } else {
                  // 非Promise 就直接成功
                  resolve(x)
                }
              } catch (e) {
                // 处理报错
                reject(e)
                throw new Error(e)
              }
            }, 0);
          }

          if (this.PromiseState === 'fulfilled') {
            // 如果当前为成功状态,执行第一个回调函数
            // 但是需要判断回调函数执行完成后的结果,所以需要将回调函数包装一下
            resolvePromise(onFulfilled)
          } else if (this.PromiseState === 'rejected') {
            // 如果当前为失败状态,执行第二个回调函数
            resolvePromise(onRejected)
          } else if (this.PromiseState === 'pending') {
            // 如果状态为待定状态,暂时保存两个回调
            // 如果状态为待定状态,暂时保存两个回调
            this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
            this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected));
          }

        })
        return thenPromise
      }
      static all(promises) {
        const result = [] // 保存成功值 的数组
        let count = 0 // 判断是否调用完成
        return new MyPromise((resolve, reject) => {
          // 用于将成功回调添加进数组
          const addData = (index, value) => {
            result[index] = value // 收集 成功值
            count++ // 同时计算成功值个数
            if (count === promise.length) resolve(result) // 收集满了就执行resolve回调
          }
          // 循环获取promise
          promises.forEach((promise, idx) => {
            // 判断数组中是否有非Promise项
            if (promise instanceof MyPromise) {
              promise.then(res => {
                // 将成功回调里的数据添加到 数组中
                addData(idx, res)
              }, err => {
                reject(err) // 如果有一个错误,就执行 reject回调
              })
            } else {
              //  非promise项当做成功 添加到数组中
              addData(idx, promise)
            }
          })
        })
      }
      static race(promises) {
        return new MyPromise((resolve, reject) => {
          promises.forEach(promise => {
            if (promise instanceof MyPromise) {
              promise.then(res => resolve(res), err => reject(err))
            } else {
              resolve(promise)
            }
          })
        })
      }
      static allSettled(promises) {
        const res = [] // 保存成功值 的数组
        let count = 0 // 判断是否调用完成
        return new MyPromise((resolve, reject) => {
          // 用于将成功回调添加进数组
          const addData = (status, value, index) => {
            res[index] = {
              status,
              value
            } // 收集 成功值
            count++ // 同时计算成功值个数
            if (count === promise.length) resolve(res) // 收集满了就执行resolve回调
          }
          // 循环获取promise
          promises.forEach((promise, idx) => {
            // 判断数组中是否有非Promise项
            if (promise instanceof MyPromise) {
              promise.then(res => {
                // 将成功回调里的数据添加到 数组中
                addData('fulfilled', res, idx)
              }, err => {
                addData('rejected', err, idx)
              })
            } else {
              //  非promise项当做成功 添加到数组中
              addData('fulfilled', promise, idx)
            }
          })
        })
      }
      static any(promises) {
        let count = 0
        return new MyPromise((resolve, reject) => {
          promises.forEach((promise) => {
            promise.then(val => {
              resolve(val)
            }, err => {
              count++
              if (count === promises.length) {
                reject(new AggregateError('All promises were rejected'))
              }
            })
          })
        })
      } 

相关文章

网友评论

    本文标题:Promise原理

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