promise 以及语法糖 | 客服服务营销数智化洞察_晓观点
       

promise 以及语法糖

在了解这个之前我们先了解什么是协程, 协程是比线程更轻量级的存在, 他不由 cpu 直接调度,而是可以通过用户来手动操作(通过程序), 在可以挂起,和开始, 可以理解成协程跑在线程上, 一个线程可以有很多个协程, 但是一个线程只能同时执行一个协程, A 协程可以开启 B 协程, 但是 A 协程必须让出控制权, 当 B 协程完成后,必须让出控制权, A 协程掌握控制权, 这样就可以只有一个协程在执行, 生成器函数的 yield 让函数暂停执行,并执行外面的函数, 通过 next 函数让函数重新执行, 协程带来的好处可以提升性能, 协程的切换并不像线程那样过多的消耗资源, 了解了协程, 就知道为什么要生成器函数了。

  • async
    • 关键字, 标识这个函数为异步, 返回一个函数返回的值是 Promise 类型数据
  • await
    • 关键字, 等待一个 Promise 的兑换以及值, 后面跟的是一个表达式

async / await 实现原理

是 generator 和 Promise 的语法糖, 书写异步代码如同同步代码一样, async 可以理解为, 将 generator 和 自执行器的封装, await 可以理解为 yield

    // 返回一个 Promise 值
    function test(num) {
        return Promise.resolve(num * 3)
    }
    
    // 生成器函数有个特点, next 传入的值等于上一 yield 的返回值  
    function * generator() {
        const value1 = yield test(2)
        const value2 = yield test(vlaue1)
    }
    
    function generatorFunc(generators) {
        return () => {
            return new Promise((resolve, reject) => {
                const gen = generators()
                
                const doYield = (val) => {
                    let res 
                    try {
                        res = gen.next() // 满足迭代器协议, 返回 {value: ..., done: ..}
                    } catch (e) {
                        reject(e)
                    }
                    
                    if (res.done) { // 迭代完成
                        return resolve(res.value) // 返回这个最终值
                    } else {
                        // 没有迭代完成, 继续迭代
                        res.value.then(result => doYield(result))
                    }
                }
                doYield() // 执行这个函数
            })
        }
    }
    
    // 外部调用
    generatorFunc(generator)()

Promise

Promise 的作用是什么?

  • 解决回调地狱问题, 采用 then 的方法处理异步回调
  • 统一的错误处理机制, catch 方法可以捕捉到错误的发生
  • 支持链式调用,使代码简洁
  • 统一的 API, 各种异步操作, 都使用同样的方法处理

thenable 对象是什么?

拥有 then 方法的函数或对象,为了兼容以前社区中实现的 then, 在 Promise 被发布前社区就存在一些实现, 需要注意一点, Promise 对象本身就是一个 thenable 对象

var o = { then: function() {} }; // o是thenable对象
 
var f = function() {};
f.then = function() {}; // f是thenable函数

使用 ES6 的方式实现

const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'

// 工具函数, 处理 then 方法
const util = (execFun, value, resolve, reject) => {
    try {
        const val = execFun(value)
        resovel(val)
    } catch (err) {
        reject(err)
    }
}


class MyPromise {
   constructor(executor) {
       // promise 的状态
       this.status = PROMISE_STATUS_PENDING
       // 成功的结果
       this.value = undefined
       // 失败的原因
       this.reason = undefined
       // 存放成功的回调
       this.onFulFills = []
       // 存放失败的回调
       this.onRejecteds = []
       
       // 成功的执行函数
       const resolve = (value) => {
           if (this.status === PROMISE_STATUS_PENDING) {
               // 考虑传入的值就是一个 Promise 对象, 直接将他的兑换值返回
               if (value instanceof MyPromise) {
                   value.then(resolve, reject)
                   return
               }
               
               // 如果传入的值是一个 thenable 
               if (value !== null && (typeof value === 'function' || typeof vlaue === 'object')) {
                   let then
                   try {
                       then = value.then 
                   } catch (err) {
                       reject(err)
                   }
                   // 如果 then 是一个函数, 可以认为他符合条件
                   if (typeof then === 'function') {
                       let called = false // 避免多次调用, 避免 resolve 的时候又传入 Promsie 对象,因为 Promsie 本身就是一个 thenable 对象
                       try {
                          then.call(value, (res) => {
                            if (called) return 
                            called = true
                            resovle(res)
                          }, (rej) => {
                            if (called) return 
                            called = true
                            reject(rej)
                          })
                       } catch (err) {
                           reject(err)
                       }
                   }
               }
           
               queueMicrotask(() => {
                   if (this.status !== PROMISE_STATUS_PENDING) return
                   this.status = PROMISE_STATUS_FULFILLED
                   this.value = value
                   this.onFulFills.forEach(fn => {
                       fn(this.value)
                   })
               })
           }
       }
      
       // 失败的执行函数
       const reject = (reason) => {
           if (this.status === PROMISE_STATUS_PENDING) {
           // 考虑传入的值就是一个 Promise 对象, 直接将他的兑换值返回
               if (value instanceof MyPromise) {
                   value.then(resolve, reject)
                   return
               }
               
               // 如果传入的值是一个 thenable 
               if (value !== null && (typeof value === 'function' || typeof vlaue === 'object')) {
                   let then
                   try {
                       then = value.then 
                   } catch (err) {
                       reject(err)
                   }
                   // 如果 then 是一个函数, 可以认为他符合条件
                   if (typeof then === 'function') {
                       let called = false // 避免多次调用
                       try {
                          then.call(value, (res) => {
                            if (called) return 
                            called = true
                            resovle(res)
                          }, (rej) => {
                            if (called) return 
                            called = true
                            reject(rej)
                          })
                       } catch (err) {
                           reject(err)
                       }
                       return 
                   }
               }
               
               queueMicrotask(() => {
                   if (this.status !== PROMISE_STATUS_PENDING ) return 
                   this.status = PROMISE_STATUS_REJECTED
                   this.reason = reason
                   this.onRejecteds.forEach(fn => {
                       fn(this.reason)
                   })
               })
           }
       }
       
       // 执行函数
       try {
           executor(resolve, reject)
       } catch (err) {
           reject(err)
       }
       
       // ==== 原型身上的方法 ====
       
       // 实现 then 方法
       then (onFulfilled, onRejected) {
          // 当不传 onRejected 回调函数, 也能将状态传递下去
          const defaultOnRejected = (err) => {
             throw err
          }

          onRejected = onRejected || defaultOnRejected

          // 当不传 onFulfilled 回调函数, 也能将状态传递下去
          const defaultOnRejected = (value) => value

          onFulfilled = onFulfilled || defalultOnRejected
          
          // 上面的 default 作用是, 即使不传对应回调函数, 也会默认将状态传递下去, 解决链式掉调用时出现的问题

          return new MyPromise ((resolve, reject) => {
              // 状态已经锁定, 再调用 then 方法, 判断状态, 并且要传入对应回调函数后再执行
              if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
                  util(onFulfilled, this.value, resolve, reject)
              }

              if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
                  util(onRejected, this.reason, resolve, reject)
              }

              // 状态还没有被锁定
              if (this.status === PROMISE_STATUS_PENDING) {
                  this.onFulFills.push((value) => {
                      util(onFulfilled, value, resolve, reject)
                  })

                  this.onRejecteds.push(reason => {
                      util(onRejected, reason, resolve, reject)
                  })
              }
          })
       }
       
       // 当出现错误时可以捕获错误结果, MDN 上对他的描述是 Promise.prototype.then(undefined, onRejected) 的简写
       catch (onRejected) {
           return this.then(undefined, onRejected)
       }
       
       // Promise.prototype.then(onFinally, onFinally) 的简写, 不接收任何值, 与上一个 Promise 保持等效的状态
       
       /**
         等效Promise指的是两个Promise对象在行为上是相同的,
            即它们的状态(fulfilled、rejected)和值(或错误)是相同的。
            这意味着如果你有一个Promise P,另一个Promise Q是等效于P的,那么无论P是成功还是失败,Q都会以相同的方式成功或失败。

         then方法返回的新Promise是指
            当你调用一个Promise的.then()方法时,这个方法会返回一个新的Promise对象。
            这个新的Promise对象会根据原Promise对象的状态和.then()方法中提供的处理函数来决定自己的状态和值。
            如果原Promise成功,.then()方法中的成功处理函数会被调用,其返回值(或抛出的错误)将决定新Promise的状态和值;
            如果原Promise失败,.then()方法中的失败处理函数会被调用,其返回值(或抛出的错误)将决定新Promise的状态和值。
     */
       finally (onFinally, onFinally) {
           return this.then( () => onFinally(), () => onFinally())
       }
   }    
   
   // ===== 静态方法 =====
   static resolve (value) {
       return new MyPromise((resolve, reject) => resolve(value))
   }
   
   static reject (reason) {
       return new MyPromise((resolve, reject) => reject(reason))
   }
   
   
   // 接收一个 Promise 可迭代数组,当出现错误时会返回带错误的 Promise 结果值, 如果都成功被兑现会返回一个带成功值的 Promise 数组对象
   static all (promises) {
       return new MyPromise((resolve, reject) => {
           // 用于存储成功的值
           const values = []
           promises.forEach(item => {
               try {
                   item.then(res => {
                       values.push(res)
                       if (values.length === promises.length) {
                           resolve(values)
                       }
                   }, err => {
                       reject(err)
                   })
               } catch (err) {
                   reject(err)
               }
           })
       })
   } 
   
   // 和 all 方法类似, 但是返回的值结构有所不同, 并且他会记录所有的结果
   static allSettled (promises) {
       return new Promise((resolve, reject) => {
           const values = []
           promises.forEach(item => {
               try {
                   item.then(res => {
                       values.push({
                           status: PROMISE_STATUS_FULFILLED
                           value: res
                       })
                       if (values.length === promises.length) {
                           resolve(values)
                       }
                   }, err => {
                       values.push({
                           status: PROMISE_STATUS_REJECTED
                           reason: err
                       })
                       if(vlaues.length === promises.length) {
                           resovle(values)
                       }
                   })
               } catch (err) {
                   reject(err)
               }
           })
       })
   }
   
   // 返回最快被兑现的值, 无论是失败还是成功的结果
   static race (promises) {
       return new MyPromise((resolve, reject) => {
           promises.forEach(promise => {
               promise.then(resolve, reject)
           })
       })
   }
   
   // 静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。
   // 当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝, 这句话表明我们需要记录所有的拒绝原因, 当他全部失败时会返回出去
   static any (promises) {
       return new MyPromise((resovel, reject) => {
           const reasons = []
           promises.forEach(promise => {
              promise.then(resovle, err => {
                  reasons.push(err)
                  if (reasons.length === promise.length) {
                      reject(new AggregateError(reaons, 'All promise were rejected'))
                  }
              })
           })
       })
   }
}

ES5 实现

const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'

function MyPromise (executor) {
    const _this = this
    this.status = PROMISE_STATUS_PENDING
    this.value = undefinde
    this.reason = undefinde
    this.onFulfills = []
    this.onRejected = []
     
    function resovle (value) {
        if (_this.status === PROMISE_STATUS_PENDING) {
            _this.value = vlaue
            _this.status = PROMISE_STATUS_FULFILLED
            // 执行成功的函数
            _this.onFulfills.forEach(fn => {
                fn(_this.value)
            })
        }
    }
    
    function reject (reason) {
        if (_this.status === PROMISE_STATUS_PENDING){
            _this.reason = reason
            _this.status = PROMISE_STATUS_REJECTED
            _this.onRejecteds.forEach(fn => {
                fn(_this.reason)
            })
        }
    }
    
    try {
        executor(resolve, reject)
    } catch (err) {
        reject(err)
    }   
}

// then 方法
MyPromise.prototype.then = (onFulfill, onReject) => {
    // 什么也不传, 也要将状态传递下去, 满足 then 值传递特性
    onFulfill = onFulfill ? onFulfill : (value) => value
    onReject = onReject ? onReject : (err) => throw err
    
    const promise = new Promise((resolve, reject) => {
        // 处理状态已经敲定后再调用 then 方法的情况
        if (this.staus === PROMISE_STATUS_FULFILLED){
             util(onFulfill, this.value, resovle, reject)
        }

        if (this.status === PROMISE_STATUS_REJECTED) {
             util(onReject, this.reason, resovle, reject)
        }

        if (this.status === PROMISE_STATUS_PENDING) {
            this.onFulfills.push(() => {
                queueMicrotask(() => {
                    try {
                        const val = onFulfill(this.value)
                        util(promise, val, resolve, reject)
                    } catch (err) => {
                        reject(err)
                    }
                })
            })
            
            this.onRejecteds.push(() => {
                queueMicrotask(() => {
                    try {
                        const reason = onReject(this.reason)
                        util(promise, reason, resolve, reject)
                    } catch (err) {
                        reject(err)
                    }
                })
            })
        }
    })
    
    return promise
}

// 处理返回值, 与 Es6 实现的不同是, then 返回值都放在这里面处理了
function util (Promsie, value, resovle, reject) {
    // 这一步是为什么?用户的返回值可能就是调用的那个 promise 对象(无法预测用户的行为)
    if (Promise === value) {
        reject(new Error("请避免循环引用"))
    }
    let called // 防止被多次调用
    if (value != null && (typeof value === "function" || typeof value === "object")) {
        let then
        try {
            then = value.then   
        } catch (err) {
            reject(err)
        }
        
        if (typeof then === "function") {
            try {
                then.call(value, (y) => {
                    if (called) return 
                    called = true
                    util(Promise, y, resovle, reject) // 直到他是一个非 thenable 的值
                }, (err) => {
                    if (called) return 
                    called = true
                    reject(err)
                })
            } catch (err) {
                reject(err)
            }
        } else {
            resovle(value)
        }
    } else {
       resovle(value)
    }
}

MyPromise.prototype.catch = function (onReject) {
    return this.then(undefined, onReject)
}

MyPromise.prototype.finally = function (onFinally, onFinally) {
    return this.then(() => onFinally(), () => onFinally())
}

MyPromise.resolve = function (value) {
    return new MyPromise((resolve, reject) => resolve(value))
}

MyPromise.reject = function (reason) {
    return new MyPromise((resolve, reject) => reject(reason))
}

MyPromise.all = function (promises) {
    return new MyPromise((resolve, reject) => {
       const values = []
        try {
            promises.forEach(promise => {
              promise.then(res => {
                  values.push(res)
                  if (values.length === promises.length) {
                      resovle(values)
                  }
              }, err => {
                  reject(err)
              })  
            })
        } catch (err) {
            reject(err)
        }
    })
}

MyPromise.allSettled = function (promises) {
    return new MyPromise((resovle, reject) => {
        const values = []
        try {
            promises.forEach(promise => {
                promise.then(res => {
                    values.push({
                        status: PROMISE_STATUS_FULFILLED,
                        value: res
                    })
                    
                    if (values.length === promises.length) {
                      resovle(values)
                    }
                }, err => {
                    values.push({
                       status: PROMISE_STATUS_REJECTED
                       reason: err
                    })
                    if(vlaues.length === promises.length) {
                       resovle(values)
                    }
                })
            })
        } catch (err) {
            reject(err)
        }  
    })
}

MyPromise.race = function (promises) {
    return new MyPromise((resovle, reject) => {
        try {
            promises.forEach(promise => {
                promise.then(resovle, reject)
            })
        } catch (err) {
            reject(err)
        }  
    })
}

MyPromise.any = function (promises) {
   return new MyPromise((resovle, reject) => {
       const reasons = []
       try {
          promsies.forEach ((promise) => {
               promise.then(resolve, err => {
                   reasons.push(err)
                   if (reasons.length === promises.length) {
                       reject(new AggregateError(reaons, 'All promise were rejected'))
                   }
               })
          })
       } catch (err) {
           reject(err)
       }  
   })
}
免费试用 更多热门智能应用                        
(0)
研发专家-luck_luo研发专家-luck_luo
上一篇 2024年12月4日
下一篇 2024年12月19日

相关推荐