JavaScript

[深入19] 手写Promise

2021-09-22  本文已影响0人  woow_wu7
image

导航

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

[react] Hooks

[部署01] Nginx
[部署02] Docker 部署vue项目
[部署03] gitlab-CI

[源码-webpack01-前置知识] AST抽象语法树
[源码-webpack02-前置知识] Tapable
[源码-webpack03] 手写webpack - compiler简单编译流程
[源码] Redux React-Redux01
[源码] axios
[源码] vuex
[源码-vue01] data响应式 和 初始化渲染
[源码-vue02] computed 响应式 - 初始化,访问,更新过程

前置知识

一些单词

race:比赛,竞赛
Settled:结束

execute:执行
executor:执行者

detected:检测

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时被调用,参数分别是终值和拒因,第二个参数函数可选
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()捕获

手写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()方法的主要作用

rejected()方法的主要作用

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()方法没有传参时

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

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

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() 的链式调用

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()模拟实现

说明:
1. Promise.all()返回的是一个新的promise,即可以使用then获取resolve和reject的结果
2. 参数是一个数组或者具有Iterator接口的数据
3. 如果参数数组成员不是promise,就会被Promise.resolve()转成promise对象
4. resolve的时机是所有参数成员都变成fulfilled状态时
5. 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/1190000012820865
手写promise https://juejin.im/post/6844903872842956814

上一篇下一篇

猜你喜欢

热点阅读