关于javascript:深入19-手写Promise

29次阅读

共计 20429 个字符,预计需要花费 52 分钟才能阅读完成。

  • 2021/04/10 温习

导航

[[深刻 01] 执行上下文](https://juejin.im/post/684490…
[[深刻 02] 原型链](https://juejin.im/post/684490…
[[深刻 03] 继承](https://juejin.im/post/684490…
[[深刻 04] 事件循环](https://juejin.im/post/684490…
[[深刻 05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490…
[[深刻 06] 隐式转换 和 运算符](https://juejin.im/post/684490…
[[深刻 07] 浏览器缓存机制(http 缓存机制)](https://juejin.im/post/684490…
[[深刻 08] 前端平安](https://juejin.im/post/684490…
[[深刻 09] 深浅拷贝](https://juejin.im/post/684490…
[[深刻 10] Debounce Throttle](https://juejin.im/post/684490…
[[深刻 11] 前端路由](https://juejin.im/post/684490…
[[深刻 12] 前端模块化](https://juejin.im/post/684490…
[[深刻 13] 观察者模式 公布订阅模式 双向数据绑定](https://juejin.im/post/684490…
[[深刻 14] canvas](https://juejin.im/post/684490…
[[深刻 15] webSocket](https://juejin.im/post/684490…
[[深刻 16] webpack](https://juejin.im/post/684490…
[[深刻 17] http 和 https](https://juejin.im/post/684490…
[[深刻 18] CSS-interview](https://juejin.im/post/684490…
[[深刻 19] 手写 Promise](https://juejin.im/post/684490…
[[深刻 20] 手写函数](https://juejin.im/post/684490…

[[react] Hooks](https://juejin.im/post/684490…

[[部署 01] Nginx](https://juejin.im/post/684490…
[[部署 02] Docker 部署 vue 我的项目](https://juejin.im/post/684490…
[[部署 03] gitlab-CI](https://juejin.im/post/684490…

[[源码 -webpack01- 前置常识] AST 形象语法树](https://juejin.im/post/684490…
[[源码 -webpack02- 前置常识] Tapable](https://juejin.im/post/684490…
[[源码 -webpack03] 手写 webpack – compiler 简略编译流程](https://juejin.im/post/684490…
[[源码] Redux React-Redux01](https://juejin.im/post/684490…
[[源码] axios ](https://juejin.im/post/684490…
[[源码] vuex ](https://juejin.im/post/684490…
[[源码 -vue01] data 响应式 和 初始化渲染 ](https://juejin.im/post/684490…
[[源码 -vue02] computed 响应式 – 初始化,拜访,更新过程 ](https://juejin.im/post/684490…

前置常识

一些单词

race:较量,比赛
Settled:完结

execute:执行
executor:执行者

detected:检测

promise 温习

  • 办法

    • promise.then() —————————- 返回新的 promise
    • promise.catch() ————————— 返回新的 promise
    • promise.finally() ————————– 不论状态如何都会执行
    • promise.all() —————————— 所有 resolve 则 fulfilled,一个 reject 则 rejected
    • promise.any() —————————- 一个 resolve 则 fulfilled,所有 reject 则 rejected
    • promsie.race() —————————- 第一个 resolve 则 fulfiled,第一个 reject 则 rejected
  • 特点

    • 对象的状态不受外界影响,只有异步操作的后果才能够决定以后是哪一种状态,任何其余操作都不能扭转这个状态
    • 状态一旦扭转就不会再变,任何时候都能够失去这个后果
  • <font color=red>毛病</font>

    • 无奈勾销 promise,一旦新建就会立刻执行,中途无奈勾销
    • 如果不设置回调,外部抛出的谬误,不会反馈到内部
    • 当处于 pending 状态时,无奈得悉以后停顿到哪一个阶段 (刚开始? 行将完结?)
  • Promise 的用法

    const promise = new Promise(function(resolve, reject) {
    // ... some code
    if (/* 异步操作胜利 */){resolve(value);
    } else {reject(error);
    }
    });
    
    promise.then(function(value) {// success}, function(error) {// failure});
    
    
    阐明:(1) Promise 构造函数承受一个 (函数) 作为参数
    (2) (参数函数) 又承受两个函数作为参数 (resolve 函数) 和 (reject 函数)
    (3) resolve() 
      - 函数是在状态由 pending->fulfilled 时,即胜利时调用,并将异步操作的后果作为参数传递进来
      - resolve()函数的参数,除了是失常的 ( 值) 以外,还能够是一个 (promise 实例)
    (4) reject() 
      - 函数是在状态由 pending->rejected 时,即失败时调用,并将异步操作报出的谬误作为参数传递进来
      - reject()函数的参数,通常是 ( Error 对象) 的实例
    (5) then() 办法承受两个函数作为参数
      - 第一个参数函数在 resolve 时被调用
      - 第二个参数函数在 reject 时被调用,参数别离是终值和拒因,第二个参数函数可选
  • resolve()

    • resolve()和 reject()两个函数并不会终止 promise,前面的代码还是会执行
    • <font color=red> 通常用 return resolve() return reject() 这样的形式完结 promise 构造函数代码的运行 </font>
    • <font color=blue>resolve() 函数的参数是一个 promise 实例的状况</font>
    let count = 1
    setInterval(() => {console.log(count++)}, 1000)
    
    const p1 = new Promise(function (resolve, reject) {setTimeout(() => {console.log('p1 中的代码开始执行')
      reject(new Error('fail'))
    }, 3000)
    })
    
    const p2 = new Promise(function (resolve, reject) {setTimeout(() => {console.log('p2 中的代码开始执行');
      resolve(p1)
    }, 1000)
    })
    
    p2
    .then(result => console.log(result))
    .catch(error => console.log(error))
    
    
    剖析:(1) p2 的状态在 1s 后扭转为胜利,resolve(p1)的参数 p1 还是一个 promise,导致 p2 的状态生效
    (2) p2 的状态生效,则 p2 的状态由 p1 决定
    (3) p1 的状体在 3s 后扭转为失败,reject(new Error('fail')),所以在 3s 后,p2 的状态也变成了失败
    (4) p2 的失败状态由 p2.catch()捕捉
  • then()

    • <font color=red> 返回一个新的 promise 实例,因而能够采纳链式写法 </font>
    • <font color=blue> 如果 then()办法链式调用,上一个 then()可能返回的是一个 promise 实例,则后一个 then()的回调函数须要期待前一个 then()状态扭转后才会调用 </font>
  • catch()

    • <font color=red> 返回一个新的 promise 实例,次要作用是捕捉 promise 过程中的谬误 </font>
    • <font color=blue>catch()办法返回的是一个 promise 对象,因而.catch()前面能够持续调用.then()</font>
    • catch()是 .then(null, rejection).then(undefined, rejection)的别名,用于指定产生 谬误 时的 回调函数
    • 只有是 catch()后面的 then()和 promise 外部抛出的谬误都能被 catch()捕捉
    • 留神:

      • 一个在 then()中只须要增加胜利状态后的回调,而失败的状态由 catch()来负责捕捉
  • finally()

    • <font color=red> 不论 promise 对象最初是什么状态,都会执行的操作 </font>
    • <font color=blue>finally()的回调函数不承受任何参数,因为 finally()的回调函数中的操作和状态无关 </font>
  • all()

    • 所有 resolve()则 fulfilled,一个 reject()则 rejected
  • any()

    • 一个 resolve()则 fulfilled,所有 reject()则 rejected

      • 和 all()相同
  • race()

    • 一个 resolve()则 fulfilled,一个 reject()则 rejected
  • allSettled()

    • 在所有参数的实例都返回后果时,包装实例才会完结
    • 比方期待所有申请实现,无论成功失败,都完结 loading 动画

手写 Promise

class Promise {constructor(executor) {
    // 参数不是函数,报错
    if (typeof executor !== 'function') {throw new TypeError(`Promise resolver ${executor} is not a function`)
    }
    this.init() // 初始化值
    try {executor(this.resolve, this.reject)
    } catch (err) {// 应用 try...catch 的目标是为了把 executor()中的谬误抛出给 then 的回调去捕捉
      this.reject(err)
    }
  }


  init = () => {
    this.value = null // 终值
    this.reason = null // 拒因
    this.state = Promise.PENDING // 状态

    this.onFulfilledCallbacks = [] // 胜利回调, 在 then()办法中 push,resolve()时执行
    this.onRejectedCallbacks = [] // 失败回调,在 then()办法中 push,reject()时执行}

  resolve = (value) => {// 胜利后的一系列操作 (状态的扭转,胜利回调的执行)
    // 状态的扭转:pending -> fulfilled

    // console.log(this.constructor === Promise) // true
    // this 在箭头函数中,作用域绑定在父级执行上下文,即定义时所在的对象
    // 即 this 相当于父级的 this,这里又是在勾走函数中,所以 this 指向了实例对象 
    if (this.state === Promise.PENDING) {
      this.state = Promise.FULFILLED
      this.value = value

      this.onFulfilledCallbacks.forEach(fn => fn(this.value))
      // 当 promise 的参数函数中有异步操作时,then 办法会优先于 resolve()或者 reject()先执行
      // 这样就是导致执行 then()办法时,状态是 pending 状态,因为状态的扭转是在 resolve()或 reject()中扭转的,而他们因为异步都没执行
      // 这是须要用一个数组来存储未来才会执行的 onFulfilled 函数
      // 这里 push 进 onFulfilledCallbacks 的函数,将在 resolve()函数中去执行}
  }

  reject = (reason) => {// 失败后的一系列操作 (状态的扭转,失败回调的执行)
    // 状态的扭转:pending -> rejected
    if (this.state === Promise.PENDING) {
      this.state = Promise.REJECTED
      this.reason = reason

      this.onRejectedCallbacks.forEach(fn => fn(this.reason))
    }
  }

  then = (onFulfilled, onRejected) => {
    // 参数校验,穿透成果,即 then 不传任何参数具备穿透成果
    if (typeof onFulfilled !== 'function') {onFulfilled = value => value}
    // 参数校验,穿透成果,即 then 不传任何参数具备穿透成果
    if (typeof onRejected !== 'function') {
      onRejected = reason => {throw reason}
    }

    // then()办法返回的是一个新的 promse 实例
    // 因为返回新的 promise 实例,能够能够实现链式调用
    let promise2 = new Promise((resolve2, reject2) => {
      // 执行 onFulfilled 函数的条件
      if (this.state === Promise.FULFILLED) {setTimeout(() => {// 这里两头的 then()办法中的回调 onFulfilled() 函数是有返回值的
          // 两头 then()参数函数 onFulfilled()的返回值,会被当做下一个 then 回调的参数传入
          try {const x = onFulfilled(this.value)
            Promise.resolvePromise(promise2, x, resolve2, reject2)
          } catch (err) {reject2(err)
          }

        })
      }
      if (this.state === Promise.REJECTED) {setTimeout(() => {
          try {const x = onRejected(this.reason)
            Promise.resolvePromise(promise2, x, resolve2, reject2)
          } catch (err) {reject2(err)
          }

        })
      }
      if (this.state === Promise.PENDING) {
        // 如果状态是 pending
        // 当 promise 的参数函数中有异步操作时,then 办法会优先于 resolve()或者 reject()先执行
        // 这样就是导致执行 then()办法时,状态是 pending 状态,因为状态的扭转是在 resolve()或 reject()中扭转的,而他们因为异步都没执行
        // 这时须要用一个数组来存储未来才会执行的 onFulfilled 函数
        // 这里 push 进 onFulfilledCallbacks 的函数,将在 resolve()函数中去执行
        this.onFulfilledCallbacks.push((value) => {// 这里依然须要应用 setTimeout,因为这个函数是在 resolve()中执行的,如果 resolve()前面任而后同步代码,要保障同步代码先执行
          setTimeout(() => {
            try {const x = onFulfilled(value)
              Promise.resolvePromise(promise2, x, resolve2, reject2)
            } catch (err) {reject2(err)
            }
          })
        })
        this.onRejectedCallbacks.push((reason) => {setTimeout(() => {
            try {const x = onRejected(reason)
              Promise.resolvePromise(promise2, x, resolve2, reject2)
            } catch (err) {reject2(err)
            }

          })
        })
      }
    })
    return promise2
  }
}

// 这里应用动态属性,是为了防止 魔法字符串
Promise.PENDING = 'pending'
Promise.FULFILLED = 'fulfilled'
Promise.REJECTED = 'rejected'
Promise.resolvePromise = function (promise2, x, resolve, reject) {
  // x 与 promise2 相等
  if (promise2 === x) {reject(new TypeError('chainning cycle detected for promise'))
  }
  // x 是 Promise
  if (x instanceof Promise) {
    x.then(value => {// resolve(value)
      Promise.resolvePromise(promise2, value, resolve, reject)
    }, reason => {reject(reason)
    })
  } 
  else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    // x 为对象或函数
    try {
      const then = x.then
      if (typeof then === 'function') {
        then.call(
          x,
          value => {if (called) return
            called = true
            MyPromise.resolvePromise(promise2, value, resolve, reject)
          },
          reason => {if (called) return
            called = true
            reject(reason)
          }
        )
      } else {if (called) return
        called = true
        resolve(x)
      }
    } catch (e) {if (called) return
      called = true
      reject(e)
    }
  } else {resolve(x)
  }
}


const promise = new Promise((resolve, reject) => {// throw new Error('出错了')
  console.log(1)
  setTimeout(() => {console.log(4)
    resolve(6)
    console.log(5)
  })
  console.log(2)
})
  .then(
    value => {console.log(value, 'value')
      return new Promise(resolve => {
        resolve(new Promise(resolve3 => {resolve3(7)
        }))
      })
    },
    reason => {console.log(reason, 'reason')
    })
  .then(
    value => {console.log(value, 'vvvvvvvvvvvv')
    }, reason => {console.log(reason)
    })
console.log(3)



// then
  // then 中的两个参数回调函数须要异步,setTimeout 解决
  // 如果 promise 参数函数外部抛出谬误,须要在 then()中捕捉 => try ... catch
  // 如果 promise 中存在异步,then 的回调不会执行 => 因为在执行 then 办法的时,state === 'pending' 不满足执行 then 两个回调的任何一个,而当 setTimeout 中的 resolve() 执行的时,then 执行过了就不会再继续执行

new Promise()的参数必须是函数,非函数时会报错

原生:new Promise(1)
TypeError: Promise resolver 1 is not a function


模仿实现:class Promise {constructor(executor) {if (typeof executor !== 'function') {
      // 参数必须是函数,不是函数抛出谬误
      throw new TypeError(`Promise resolver ${executor} is not a function`)
    }
    executor(this.resolve, this.reject)
  }
}
const promise = new Promise()
// TypeError: Promise resolver undefined is not a function

resolve()办法的次要作用

  • (1) 把状态 (<font color=red>status</font>) 从 (<font color=red>pending -> fulfilled</font>)
  • (2) 把终值 (<font color=red>value</font>) 赋值为 resolve()函数传入的 ( <font color=red> 参数 </font>)
  • (3) 把 (<font color=red>onFulfilledCallback 数组 </font>) 中的函数,依此取出执行

    • 如果 promise 中存在异步操作时,then()比 resolve()先执行
    • 所以在 then()办法中,须要向 onFulfilledCallback 数组中 push 进一个未来在 resolve()中才会执行的函数

    rejected()办法的次要作用

  • (1) 把状态 (<font color=red>status</font>) 从 (<font color=red>pending -> rejected</font>)
  • (2) 把拒因 (<font color=red>value</font>) 赋值为 reject()函数传入的 ( <font color=red> 参数 </font>)
  • (3) 把 (<font color=red>onRejectedCallback 数组 </font>) 中的函数,依此取出执行

    • 如果 promise 中存在异步操作时,then()比 resolve()先执行
    • 所以在 then()办法中,须要向 onFulfilledCallback 数组中 push 进一个未来在 reject()中才会执行的函数
    class Promise {constructor(executor) {if (typeof executor !== 'function') {
        // 参数必须是函数,不是函数抛出谬误
        throw new TypeError(`Promise resolver ${executor} is not a function`)
      }
      this.init()
      executor(this.resolve, this.reject)
    }
    init = () => {
      this.value = null // 终值,初始化
      this.reason = null // 拒因,初始化
      this.status = Promise.PENDING // 状态,初始化时 pending
      this.onFulfilledCallbacks = [] // 胜利回调, 在 then()办法中 push,resolve()时执行
      this.onRejectedCallbacks = [] // 失败回调,在 then()办法中 push,reject()时执行}
    resolve = (value) => {if (this.status === Promise.PENDING) {
        this.status = Promise.FULFILLED
        this.value = value
        this.onFulfilledCallbacks.forEach(fn => fn(value))
      }
    }
    reject = (reason) => {if (this.status === Promise.PENDING) {
        this.status === Promise.REJECTED
        this.reason = reason
        this.onRejectedCallbacks.forEach(fn => fn(resaon))
      }
    }
    then = (onFulfilled, onRejected) => {if (this.status === Promise.FULFILLED) {onFulfilled(this.value)
      }
      if (this.status === Promise.REJECTED) {onRejected(this.reason)
      }
      if (this.status === Promise.PENDING) {this.onFulfilledCallbacks.push((value) => onFulfilled(value))
        this.onRejectedCallbacks.push((reason) => onRejected(reason))
      }
    }
    }
    
    Promise.PENDING = 'pending'
    Promise.FULFILLED = 'fulfilled'
    Promise.REJECTED = 'rejected'
    
    const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve(1)
    })
    }).then(value => {console.log(value)
    }, reason => {console.log(reason)
    })

then()办法没有传参时

  • 须要重写 onFulfilled 函数,返回以后的终值 this.value
  • 须要重写 onRejected 函数,返回以后的拒因 this.reason,并抛出

    then = (onFulfilled, onRejected) => {if (typeof onFulfilled !== this.FUNCTION) {
              // 没传 onFulfilled 参数,就重写该函数
              // 将调用参数原样返回
              // 这里没有间接写 (typeof onFulfilled !== 'function') 避免魔法字符串
              onFulfilled = value => value 
          }
          if (typeof onRejected !== this.FUNCTION) {
               // 没传 onRejected 参数,就重写该函数
               // 抛出 reason
              onRejected = reason => {throw reason}
          }
          if (this.status === this.FULFILLED) {
              // 是 fulfilled 状态是,才执行 onFulfilled 函数,参数是以后的终值
              // 即状态扭转时为胜利时,增加的回调函数
              // 这里传参和没有传参都会执行,没传参是执行重写过后的 onFulfilled
              onFulfilled(this.value)
          }
          if (this.status === this.REJECTED) {onRejected(this.reason)
          }
      }
    

then()保障执行程序 1

  • <font color=red>then()须要在同步代码执行完后,then()中的回调函数能力执行 </font>

    console.log(1)
    const promise = new Promise((resolve, reject) => {console.log(2)
    resolve(5)
    console.log(3)
    })
    .then(value => {console.log(value)
    }, reason => {console.log(reason)
    })
    console.log(4)
    
    
    问题:如何保障执行程序是  12345
    解决:then()是异步办法,即 then()办法的参数回调须要在 resolve()或 reject()办法执行后才执行,用 (定时器) 解决
    阐明:如果不必定时器执行程序是 
    
    
    then = (onFulfilled, onRejected) => {if (typeof onFulfilled !== Promise.FUNCTION) {onFulfilled = value => value}
      if (typeof onRejected !== Promise.FUNCTION) {onRejected = reason => reason}
      if (this.status === Promise.FULFILLED) {setTimeout(() => {// 用 setTimeout()来模仿异步执行 onFulfilled,保障同步代码执行后再执行 onFulfilled
          onFulfilled(this.value)
        })
      }
      if (this.status === Promise.REJECTED) {setTimeout(() => {// 用 setTimeout()来模仿异步执行 onRejected,保障同步代码执行后再执行 onRejected
          onRejected(this.reason)
        })
      }
      if (this.status === Promise.PENDING) {this.onFulfilledCallbacks.push((value) => onFulfilled(value))
        this.onRejectedCallbacks.push((reason) => onRejected(reason))
      }
    }

then()保障执行程序 2

  • <font color=red> 当 promise 中有有异步代码时,then()办法会比 resolve()先执行,此时 statuss=’pending’ 状态 </font>
  • <font color=red> 而在 then 办法中并未增加状态是 pending 状态时的相干操作时,then()中的两个回调都不会执行 </font>

    console.log(1)
    new Promise((resolve, reject) => {console.log(2)
      setTimeout(() => resolve())
     // 当这里有异步操作时,下面的代码打印只有 123,留神 4 并未打印
     // 起因是 then()办法在 resolve()办法前执行了,因为 resolve 是异步的,导致 then() 中的状态还是 pending 状态
     // 而在 then 办法中并为增加状态是 pending 状态时的相干操作
    }).then(() =>  console.log(4))
    console.log(3)
    
    
    
    问题:打印出了 123,然而并未打印 4
    剖析:1. 起因是 then()办法在 resolve()办法前执行了,因为 resolve 是异步的,导致 then() 中的状态还是 pending 状态
    2. 而在 then 办法中并为增加状态是 pending 状态时的相干操作
    解决:1. 在 then()办法中增加 pending 状态下的相干判断
        - 并向 onFulfilledCallbacks 数组中 push 一个方办法,该方中去调用 onFulfilled 办法,参数是以后的 value
        - 并向 onRejectedCallbacks 数组中 push 一个办法,该方中去调用 onRejected 办法,参数是以后的 reason
    2. 在 resolve()办法中去循环 onFulfilledCallbacks 数组,并执行外面的函数,实参是 this.value
    2. 在 reject()办法中去循环 onRejectedCallbacks 数组,并执行外面的函数,实参是 this.reason
    
    
    
    then = (onFulfilled, onRejected) => {
          ...
          if (this.status === this.PENDING) {
              // pending 状态 push 函数到 onFulfilledCallbacks 数组
              this.onFulfilledCallbacks.push(value => onFulfilled(value)) 
              this.onRejectedCallbacks.push(reason => onRejected(reason))
          }
      }
     resolve = (value) => {if (this.status === this.PENDING) {
              this.status = this.FULFILLED
              this.value = value
              this.onFulfilledCallbacks.forEach(fn => fn(this.value)) // 执行数组中的函数,并传入实参
          }
      }
    reject = (reason) => {if (this.status === this.PENDING) {
              this.status = this.REJECTED
              this.reason = reason
              this.onRejectedCallbacks.forEach(fn => fn(this.reason))
          }
      }

then()保障执行程序 3

console.log(1)
new Promise((resolve, reject) => {console.log(2)
    setTimeout(() => {resolve()
        console.log(4) // 要保障 4 比 5 先执行,因为 4 是同步代码
    })
}).then(() =>  console.log(5))
console.log(3)



问题:下面代码输入 12354,而真正的 promise 应该输入  12345
剖析:因为 resolve()前面还有同步代码,要保障前面的同步代码先执行
解决:在向 onFulfilledCallbacks 数组中 push 办法时,要再用 setTimeout 包装,让 resolve()前面的代码先执行



    then = (onFulfilled, onRejected) => {
       ...
        if (this.status === this.PENDING) {
            this.onFulfilledCallbacks.push(value => {setTimeout(() => {// 再用 setTimeout 包装,保障 resolve()前面的代码先于 then 的回调函数 执行
                    onFulfilled(value)
                }, 0)
            })
            this.onRejectedCallbacks.push(reason => {setTimeout(() => {onRejected(reason)
                }, 0)
            })
        }
    }

then() 的链式调用

  • <font color=red>then()办法返回的是新的 promise 实例,留神不是原来的,所以能够链式调用 </font>
  • <font color=red> 新的 promise 中参数函数的 resolve 的是 onFufiled 函数执行后返回的值 </font>

    then = (onFulfilled, onRejected) => {
      // 参数校验,穿透成果,即 then 不传任何参数具备穿透成果
      if (typeof onFulfilled !== Promise.FUNCTION) {onFulfilled = value => value}
      // 参数校验,穿透成果,即 then 不传任何参数具备穿透成果
      if (typeof onRejected !== Promise.FUNCTION) {onRejected = reason => reason}
      const promise2 = new Promise((resolve2, reject2) => {if (this.status === Promise.FULFILLED) {setTimeout(() => {const x = onFulfilled(this.value)
            // 将 onFulfilled 函数的返回值作为 resolve()的参数,传给新的 then() 办法
            resolve2(x)
          })
        }
        if (this.status === Promise.REJECTED) {setTimeout(() => {const x = onRejected(this.reason)
            reject2(x)
          })
        }
        if (this.status === Promise.PENDING) {this.onFulfilledCallbacks.push((value) => {setTimeout(() => {const x = onFulfilled(value)
              resolve2(x)
            })
          })
          this.onRejectedCallbacks.push((reason) => {setTimeout(() => {const x = onRejected(reason)
              reject2(x)
            })
          })
        }
      })
      return promise2
    }
    更具体
    
    then = (onFulfilled, onRejected) => {if(typeof onFulfilled !== 'function') {onFulfilled = (value) => value
          }
          if(typeof onRejected !== 'function') {onRejected = (reason) => {throw reason}
          }
          const promise2 = new Promise((resolve, reject) => {if (this.status === Promise.FULFILLED) {setTimeout(() => {
                try {const x = onFulfilled(this.value) // 将 onFulfilled 函数的返回值作为 resolve()的参数,传给新的 then() 办法
                  resolve(x) // promise2 的 resolve 的机会
                } catch(err) {reject(err) // promise2 的 reject 的机会
                }
              })
            }
            if (this.status === Promise.REJECTED) {setTimeout(() => {
                try {const x = onRejected(this.reason)
                  resolve(x)
                } catch (err) {reject(err)
                }
              })
            }
            if (this.status === Promise.PENDING) {this.onFulfilledCallbacks.push((value) => {setTimeout(() => {
                  try {const x = onFulfilled(value)
                    resolve(x)
                  } catch(err) {reject(err)
                  }
                })
              })
    
              this.onRejectedCallbacks.push((reason) => {setTimeout(() => {
                  try {const x = onRejected(reason)
                    resolve(x)
                  } catch(err) {reject(err)
                  }
                })
              })
            }
          })
    
          return promise2
        }

Promise.all()模仿实现

  • p = Promsie.all([p1, p2, p3])
  • 返回值:Promise.all() 返回一个新的 promise 实例
  • 参数:

    • (<font color=red> 参数 </font>) 是一个 (<font color=red> 数组 </font>) 或者是具备 (<font color=red>Iterator</font>) 接口类型的数据,成员都是 promsie 实例
    • 如果不是 promsie 实例就会调用 Promsie.resolve()转成 promsie 实例
  • 作用:

    • 如果所有参数数组成员的状态,都变成了 fulfilled,则整个状态变成 fulfilled

      • 此时 p1,p2,p3 中 resolve()的返回值,将组成一个数组,传递给 p 的回调函数
    • 如果有一个参数数组成员的状态变成了 rejected,则整个状态变成了 rejected

      • 此时,第一个被回绝的 reject()的返回值,会传递给 p 的回调函数
  • Promise.all()返回的是一个新的 promise,即能够应用 then 获取 resolve 和 reject 的后果
  • 参数是一个数组或者具备 Iterator 接口的数据
  • 如果参数数组成员不是 promise,就会被 Promise.resolve()转成 promise 对象
  • resolve 的机会是所有参数成员都变成 fulfilled 状态时
  • reject 的机会是只有有一个 rejected 状态时

    Promise.all = (promises) => {
    // 返回一个新的 promise 实例
    return new Promise((resolve, reject) => {

      const arr = []
      let count = 0 // 记录 fulfilled 状态的 promise 个数
      const promiseArr = Array.from(promises) // 参数除了数组还能够是具备 Iterator 接口的数据类型
      const len = promiseArr.length
      for (let i = 0; i < len; i++) {Promise.resolve(promiseArr[i]).then(value => { // 如果参数不是 promise,会调用 Promise.resolve()转成 promise
              count ++ // 进入这里,示意胜利的回调,即 fulfilled 状态
              arr[i] = value // 将该胜利的 promise 装进数组
              if (count === len) {console.log(count, 'count')
                  resolve(arr)
                  // 如果 count 和数组总长度相等,阐明都是 fulfilled 状态了
                  // 所有 resolve 的机会就是所有都变成 fulfilled 状态是 resolve
              }
          }, reject) // 这里写的不欠缺,请看上面的最新补充
      }

    })
    }

    const a = Promise.resolve(1)
    const b = Promise.resolve(2)
    const c = new Promise(resolve => {
    setTimeout(() => {

      resolve(33)

    })
    })

    Promise.all([a, b, c]).then(value => console.log(value, ‘value’))

2021/4/ 7 批改 Promise.all 模仿实现

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    // 手写 Promise.all
    // 1. Promise.all 返回的是一个新的 promise
    // 2. Promise.all 的参数是一个数组,成员是 promise 对象,如果不是 promise 对象会先把参数转成 promise
    // 3. 所有成员 fulfilled 则整个状态变成 fulfilled
    // 4. 一个 rejected 则整个状态变成 rejected

    const promise1 = Promise.resolve(1)
    const promise2 = Promise.resolve(2)
    const promise3 = Promise.resolve(3)
    const promise4 = Promise.reject(new Error('出错了'))

    Promise.all2 = (promises) => {return new Promise((resolve, reject) => {// Promise.all()返回一个新的 promise 对象
        const promisesArr = Array.from(promises)
        const len = promisesArr.length

        let count = 0
        const results = []

        for (let i = 0; i < len; i++) {Promise.resolve(promisesArr[i]).then(value => { // 如果参数不是 promise 则先转成 promise
            count++
            results.push(value)
            if (results.length === len) {resolve(results) // 当数组整个遍历完后,都没产生谬误的状况下,resolve(results) 整个终值数组
            }
          }, reason => reject(reason)) // 只有一个产生谬误,整个 reject 最先产生的拒因
        }
      })
    }

    Promise.all2([promise1, promise2, promise3]) // fulfilled
      .then(value => console.log(value))
      .catch(err => console.log(err))

    Promise.all2([promise1, promise2, promise3, promise4]) // rejected
      .then(value => console.log(value))
      .catch(err => console.log(err))
  </script>
</body>
</html>

Proimse.race()模仿实现

Promise.race = (promises) => {return new Promise((resolve, reject) => {const promiseArr = Array.from(promises)
        const len = promises.length

        for(let i = 0; i < len; i++) {Promise.resolve(promiseArr[i]).then(value => {resolve(value) // 间接 resolve 第一个 then 是胜利时的回调函数接管到的终值
          })
        }
      })
    }

总结遇到的一些面试题 2021/04/10

(1) promise 面试题 1

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    console.log(1)
    setTimeout(() => { // 定时器 A
      console.log(2);
      Promise.resolve().then(() => { // Promise D
        console.log(3)
      })
    })
    new Promise((resolve, reject) => { // Promise B
      console.log(4)
      resolve(5)
    }).then((data) => {console.log(data)
    })
    setTimeout(() => { // 定时器 C
      console.log(6)
    })
    console.log(7)
/****
         答案:1 4 7 5 2 3 6
    
         剖析:1. 第一次事件循环
         同步工作:1
         宏工作:[A, C]
         微工作:[B]
         输入:1 4 7
    
         2. 第二次事件循环
         遍历所有微工作[B] => 5
         取出第一个宏工作[A] => 2 , 并将微工作 D 增加进工作队列,此时微工作队列 [D]
         输入:5 2
    
         3. 第三次事件循环
         遍历所有微工作[D] => 3
         取出第一个红工作[C] -> 6
         输入:3 6
*/
  </script>
</body>
</html>

(2) promise 面试题 2

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    console.log(1)
    // A promise
    new Promise((resolve) => {console.log(2)
      resolve()
      console.log(3)
    }).then(res => { // E then
      console.log(4)
      // C 定时器
      setTimeout(() => console.log(5))
    })
    console.log(6)
    // B 定时器
    setTimeout(() => {console.log(7)
      // D promise
      new Promise((resolve) => {console.log(8)
        resolve()}).then(() => console.log(9)) // F then
    })
    console.log(10)
    /**
     * 第一轮 Event loop
     * 1 => 同步工作,进入函数调用栈,立刻执行
     * A => A 的回调立刻执行
     *      2 => 同步工作,立刻执行
     *      E => 微工作,进入微工作队列
     *      3 => 同步工作,立刻执行
     * 6 => 同步工作,立刻执行
     * B => 宏工作,B 的回调进入宏工作队列
     * 10 => 同步工作,立刻执行
     * 此时执行状况如下:* 输入:1,2,3,6,10
     * 微工作:[E]
     * 宏工作:[B]
     *
     * 第二轮 Event loop
     * 清空微工作队列,取出宏工作队列的第一个成员
     * E => 4 同步工作,立刻执行
     *      C 宏工作,进入宏工作队列,此时的宏工作队列 [B, C]
     * B => 7 同步工作,立刻执行
     *      D promise 的回调立刻执行
     *        => 8 同步工作,立刻执行
     *        => F 微工作,进入微工作队列,此时的微工作队列 [F]
     * 此时执行状况如下:* 输入:4,7,8
     * 微工作:[F]
     * 宏工作:[C]
     *
     * 第三轮 Event loop
     * 清空微工作队列,取出宏工作队列的第一个成员
     * F => 9 同步工作,立刻执行
     * C => 5 同步工作,立刻执行
     *
     * 总的输入程序:1,2,3,6,10,4,7,8,9,5
     */
  </script>
</body>
</html>

材料

手写 promise https://segmentfault.com/a/11…
手写 promise https://juejin.im/post/684490…

正文完
 0