ES6 Promise 封装原理与实现详解

作者:青柠时间:2026-10-22 20:57:33浏览:113

本文详细解析 ES6 中 Promise 的核心机制,并逐步演示如何从零封装一个 MyPromise 类。内容涵盖同步与异步任务的状态管理、then 方法的链式调用逻辑、返回值处理以及 Promise.all 等静态方法的实现原理,帮助开发者深入理解异步编程的最佳实践。

Promise 基础概念与特点

原生Promise解析

简介

Promise 是异步编程的一种解决方案,相较于传统的回调函数和事件机制,它更加合理且功能强大。

从概念上讲,Promise 是一个容器,用于保存未来才会结束的事件(通常是异步操作)的结果。从语法层面看,Promise 是一个对象,通过它可以获取异步操作的消息。Promise 提供了统一的 API,使得各种异步操作都可以采用相同的方法进行处理。

特点

对象的状态不受外界影响。Promise 代表一个异步操作,具有三种状态:Pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果才能决定当前处于哪种状态,其他任何操作都无法改变这一状态。

一旦状态发生改变,就不会再变,任何时候都可以得到这个结果。状态变化只有两种可能:从 Pending 变为 fulfilled 或从 Pending 变为 rejected。只要这两种情况发生,状态就凝固了,会一直保持这个结果,此时称为 resolved(已定型)。

MyPromise 类的同步任务封装

利用es6进行Promise封装

处理同步任务

原生方法调用方式


  new Promise((resolve,reject)=>{
    resolve(1)
  }).then(res=>{
    console.log(res) //1
  })

同步封装思考

1. 由调用方式可见 Promise 是一个类。 2. 它接收一个回调函数,这个回调函数接受 resolve 和 reject 方法作为参数。 3. 当状态改变后执行 then 方法,并将 resolve 或 reject 的结果作为 then 方法接受回调函数的参数。


  class Mypromise{
    constructor(callback){
      this.status='pendding'
      //成功结果
      this.s_res = null
      // 失败结果
      this.f_res = null
      callback((arg)=>{ // 使用箭头函数this不会丢失
       // 改变状态为成功
       this.status = 'fulfilled'
       this.s_res = arg
      },(arg)=>{
        // 改变状态为失败
        this.status = 'rejected'
        this.f_res = arg 
      })
    }
    then(onresolve,onreject){
      if(this.status === 'fulfilled'){ // 当状态为成功时
        onresolve(this.s_res)
      }else if(this.status === 'rejected'){ // 当状态为失败时
        onreject(this.f_res)
      }
    }
  }

异步任务与微任务处理机制

处理异步任务

原生调用方式


  new Promise((resolve,reject)=>{
    setTimeOut(()=>{
      resolve(1)
    },1000)
  }).then(res=>{
    console.log(res)
  })

异步封装思考

1. 根据 JS 执行机制,setTimeout 属于宏任务,then 回调函数属于微任务。当主线程执行完成后,会从异步队列中取出本次的微任务先执行。

2. 也就是说,then 方法执行时,状态还没有改变。因此我们需要将 then 方法执行的回调保存起来,等到异步代码执行完成后,再统一执行 then 方法的回调函数。


  class Mypromise{
    constructor(callback){
      this.status='pendding'
      //成功结果
      this.s_res = null
      // 失败结果
      this.f_res = null
      this.query = [] // ++ 
      callback((arg)=>{ // 使用箭头函数this不会丢失
       // 改变状态为成功
       this.status = 'fulfilled'
       this.s_res = arg
       // 当状态改变后,统一执行then方法的回调
       this.query.forEach(item=>{
         item.resolve(arg)
       })
      },(arg)=>{
        // 改变状态为失败
        this.status = 'rejected'
        this.f_res = arg 
        // 当状态改变后,统一执行then方法的回调
       this.query.forEach(item=>{
         item.reject(arg)
       })
      })
    }
    then(onresolve,onreject){
      if(this.status === 'fulfilled'){ // 当状态为成功时
        onresolve(this.s_res)
      }else if(this.status === 'rejected'){ // 当状态为失败时
        onreject(this.f_res)
      }else{ // ++ 状态没有改变
        this.query.push({ // 保存回调函数到队列中
          resolve:onresolve,
          reject:onreject
        })
      }
    }
  } 

链式调用与返回值处理逻辑

处理链式调用

原生调用方式


  new Promise((resolve,reject)=>{
    resolve(1)
  }).then(res=>{
    return res
  }).then(res=>{
    console.log(res)
  })

链式调用思考

原生的 Promise 对象的 then 方法,返回的也是一个 Promise 对象,一个新的 Promise 才能支持链式调用。

下一个 then 方法可以接受上一个 then 方法的返回值作为回调函数的参数。

主要考虑上一个 then 方法的返回值:

1. Promise 对象/具有 then 方法的对象

2. 其他值

第一个 then 方法返回一个 Promise 对象,它的回调函数接受 resFn 和 rejFN 两个回调函数作为参数,把成功状态的处理封装为 handle 函数,接受成功的结果作为参数。

在 handle 函数,根据 onresolve 返回值的不同做出不同的处理。


  class Mypromise{
    constructor(callback){
      this.status='pendding'
      //成功结果
      this.s_res = null
      // 失败结果
      this.f_res = null
      this.query = [] // ++ 
      callback((arg)=>{ // 使用箭头函数this不会丢失
       // 改变状态为成功
       this.status = 'fulfilled'
       this.s_res = arg
       // 当状态改变后,统一执行then方法的回调
       this.query.forEach(item=>{
         item.resolve(arg)
       })
      },(arg)=>{
        // 改变状态为失败
        this.status = 'rejected'
        this.f_res = arg 
        // 当状态改变后,统一执行then方法的回调
       this.query.forEach(item=>{
         item.reject(arg)
       })
      })
    }
    then(onresolve,onreject){
      return new Mypromise((resFN,rejFN)=>{
        if(this.status === 'fulfilled'){ // 当状态为成功时
          handle(this.s_res)
        }else if(this.status === 'rejected'){ // 当状态为失败时
          errBack(this.f_res)
        }else{ // ++ 状态没有改变
          this.query.push({ // 保存回调函数到队列中
            resolve:onresolve,
            reject:onreject
          })
        } 
        function handle(value){
          // 当then方法的onresolve方法有返回值时,保存其返回值,没有使用其保存的值
          let returnVal = onresolve instanceof Function && onresolve(value) || value
          // 如果onresolve方法返回的是promise对象,则调用其then方法
          if(returnVal&&returnVal['then'] instanceof Function){
            returnVal.then(res=>{
              resFN(res)
            },err=>{
              rejFN(err)
            })
          }else{
            resFN(returnVal)
          } 
        }
        function errBack(reason){
          if(onreject instanceof Function){
            let returnVal = reject(reason)
            if(typeof returnVal !== 'undenfined' && returnVal['then'] instanceof Function){
              returnVal.then(res=>{
                resFN(res)
              },err=>{
                rejFN(err)
              })
            }else{
              resFN(returnVal)
            }
          }else{
            rejFN(reason)
          }
        }
      })
    }
  } 

Promise.all 与 Promise.race 实现

Promise.all和Promise.race方法

原生调用方式

Promise.all 方法接受一个数组,数组中的每一项都是一个 Promise 实例。只有数组中的所有 Promise 实例的状态都变为 fulfilled 时,此时整个状态才会变成 fulfilled。此时数组中所有 Promise 实例的返回值组成一个新的数组,进行传递。

Promise.race 方法和 Promise.all 方法一样,如果不是 Promise 实例,就会先调用 Promise.resolve 方法,将参数转为 Promise 实例,再进行下一步处理。

只要数组中有一个参数的状态变为 fulfilled 就会进行传递。


// 将现有对象转换为Promise对象
  Mypromise.resolve = (arg)=>{
    if(typeof arg == 'undefined' || arg==null){ // 不带有任何参数
      return new Mypromise(resolve=>{
        resolve(arg)
      })
    }else if(arg instanceof Mypromise){ // 是一个Mypromise实例
      return arg
    }else if(arg['then'] instanceof Function){ // 具有then方法的对象
      return new Mypromise((resolve,reject)=>{
        arg.then(res=>{
          resolve(res)
        },err=>{
          reject(err)
        })
      })
    }else{ // 参数不是具有then方法的对象,或根本不是对象
      return new Mypromise(resolve=>{
        resolve(arg)
      }) 
    }
  }
  Mypromise.all = (arr)=>{
    if(!Array.isArray(arr)){
      throw new TypeError('参数必须是一个数组')
    }
    return new Mypromise((resolve,reject)=>{
      let i=0,result=[]
      next()
      functon next(){
        // 如果不是Mypromise实例需要转换
        Mypromise.resolve(arr[i]).then(res=>{
          result.push(res)
          i++
          if(i===arr.length){
            resolve(result)
          }else{
            next()
          }
        },reject)
      }
    })
  }
  Mypromise.race = (arr)=>{
    if(!Array.isArray(arr)){
      throw new TypeError('参数必须是一个数组')
    }
    return new Mypromise((resolve,reject)=>{
      let done = false
      arr.forEach(item=>{
        Mypromise.resolve(item).then(res=>{
          if(!done){
            resolve(res)
            done = true
          }
        },err=>{
          if(!done){
            reject(res)
            done = true
          }
        })
      })
    })
  }

状态不可逆性的实现细节

处理Mypromise状态确定不能改变的特性

在重写 callback 中的 resolve 和 reject 方法执行前,先判断状态是否为'pendding'。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章