• 手写Promise


    //Promise/A+规定的三种状态
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    
    class MyPromise {
      // 构造方法接收一个回调
      constructor(executor) {
        this._status = PENDING     // Promise状态
        this._value = undefined    // 储存then回调return的值
        this._resolveQueue = []    // 成功队列, resolve时触发
        this._rejectQueue = []     // 失败队列, reject时触发
    
        // 由于resolve/reject是在executor内部被调用, 因此需要使用箭头函数固定this指向, 否则找不到this._resolveQueue
        let _resolve = (val) => {
          //把resolve执行回调的操作封装成一个函数,放进setTimeout里,以兼容executor是同步代码的情况
          const run = () => {
            if(this._status !== PENDING) return   // 对应规范中的"状态只能由pending到fulfilled或rejected"
            this._status = FULFILLED              // 变更状态
            this._value = val                     // 储存当前value
    
            // 这里之所以使用一个队列来储存回调,是为了实现规范要求的 "then 方法可以被同一个 promise 调用多次"
            // 如果使用一个变量而非队列来储存回调,那么即使多次p1.then()也只会执行一次回调
            while(this._resolveQueue.length) {    
              const callback = this._resolveQueue.shift()
              callback(val)
            }
          }
          setTimeout(run)
        }
        // 实现同resolve
        let _reject = (val) => {
          const run = () => {
            if(this._status !== PENDING) return   // 对应规范中的"状态只能由pending到fulfilled或rejected"
            this._status = REJECTED               // 变更状态
            this._value = val                     // 储存当前value
            while(this._rejectQueue.length) {
              const callback = this._rejectQueue.shift()
              callback(val)
            }
          }
          setTimeout(run)
        }
        // new Promise()时立即执行executor,并传入resolve和reject
        executor(_resolve, _reject)
      }
    
      // then方法,接收一个成功的回调和一个失败的回调
      then(resolveFn, rejectFn) {
        // 根据规范,如果then的参数不是function,则我们需要忽略它, 让链式调用继续往下执行
        typeof resolveFn !== 'function' ? resolveFn = value => value : null
        typeof rejectFn !== 'function' ? rejectFn = reason => {
          throw new Error(reason instanceof Error? reason.message:reason);
        } : null
      
        // return一个新的promise
        return new MyPromise((resolve, reject) => {
          // 把resolveFn重新包装一下,再push进resolve执行队列,这是为了能够获取回调的返回值进行分类讨论
          const fulfilledFn = value => {
            try {
              // 执行第一个(当前的)Promise的成功回调,并获取返回值
              let x = resolveFn(value)
              // 分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
              x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
            } catch (error) {
              reject(error)
            }
          }
      
          // reject同理
          const rejectedFn  = error => {
            try {
              let x = rejectFn(error)
              x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
            } catch (error) {
              reject(error)
            }
          }
      
          switch (this._status) {
            // 当状态为pending时,把then回调push进resolve/reject执行队列,等待执行
            case PENDING:
              this._resolveQueue.push(fulfilledFn)
              this._rejectQueue.push(rejectedFn)
              break;
            // 当状态已经变为resolve/reject时,直接执行then回调
            case FULFILLED:
              fulfilledFn(this._value)    // this._value是上一个then回调return的值(见完整版代码)
              break;
            case REJECTED:
              rejectedFn(this._value)
              break;
          }
        })
      }
    
      //catch方法其实就是执行一下then的第二个回调
      catch(rejectFn) {
        return this.then(undefined, rejectFn)
      }
    
      //finally方法
      finally(callback) {
        return this.then(
          value => MyPromise.resolve(callback()).then(() => value),             //执行回调,并returnvalue传递给后面的then
          reason => MyPromise.resolve(callback()).then(() => { throw reason })  //reject同理
        )
      }
    
      //静态的resolve方法
      static resolve(value) {
        if(value instanceof MyPromise) return value //根据规范, 如果参数是Promise实例, 直接return这个实例
        return new MyPromise(resolve => resolve(value))
      }
    
      //静态的reject方法
      static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason))
      }
    
      //静态的all方法
      static all(promiseArr) {
        let index = 0
        let result = []
        return new MyPromise((resolve, reject) => {
          promiseArr.forEach((p, i) => {
            //Promise.resolve(p)用于处理传入值不为Promise的情况
            MyPromise.resolve(p).then(
              val => {
                index++
                result[i] = val
                if(index === promiseArr.length) {
                  resolve(result)
                }
              },
              err => {
                reject(err)
              }
            )
          })
        })
      }
    
      //静态的race方法
      static race(promiseArr) {
        return new MyPromise((resolve, reject) => {
          //同时执行Promise,如果有一个Promise的状态发生改变,就变更新MyPromise的状态
          for (let p of promiseArr) {
            MyPromise.resolve(p).then(  //Promise.resolve(p)用于处理传入值不为Promise的情况
              value => {
                resolve(value)        //注意这个resolve是上边new MyPromise的
              },
              err => {
                reject(err)
              }
            )
          }
        })
      }
    }
  • 相关阅读:
    一探前端开发中的JS调试技巧(转)
    JavaScript模板引擎实例应用(转)
    本周汇总
    完美解决IE8不支持margin auto问题
    移动端H5适配流程
    原型继承
    每周笔记
    一个页面多个bootstrip轮播以及一个页面多个swiper轮播 冲突问题
    如何让整个网页倾斜
    前端知识体系
  • 原文地址:https://www.cnblogs.com/lihao-bupt/p/15215001.html
Copyright © 2020-2023  润新知