Promise代码题

158 阅读3分钟

Event Loop——事件循环(JS运行机制)

1.所有同步任务都在主线程上执行,形成一个执行栈

2.而异步任务会被放置到异步处理模块,当异步任务有了运行结果,就将该函数移入任务队列。

3.一旦执行栈中的所有同步任务执行完毕,引擎就会读取任务队列,然后将任务队列中的第一个任务压入执行栈中运行。 只要主线程空了,就会去读取任务队列,该过程不断重复,这就是所谓的事件循环。

宏任务和微任务

任务队列中的都是已经完成的异步操作,异步任务分为宏任务(macrotask) 与微任务 (microtask)。宏任务会进入一个队列,而微任务会进入到另一个不同的队列,且微任务要优于宏任务执行。

宏任务:script(整体代码)、setTimeout、setInterval、I/O、事件、postMessage、 MessageChannel、setImmediate (Node.js)

微任务:Promise.then、 MutaionObserver、process.nextTick (Node.js)

process.nextTick指定的异步任务总是发生在所有异步任务之前,因此先执行process.nextTick

放入任务队列的条件 ------ 1.改变状态 2.有回调函数

1

setTimeout(()=>{
  console.log(1)
},0)
Promise.resolve().then(()=>{
  console.log(2)
})
Promise.resolve().then(()=>{
  console.log(4)
})
console.log(3)
//3 2 4 1 

先执行同步任务,再执行微任务,最后执行宏任务。

2

setTimeout(()=>{
  console.log(1)
},0)
new Promise((resolve)=>{  
  console.log(2)     //执行器函数是同步执行的
  resolve()
}).then(()=>{
  console.log(3)
}).then(()=>{
  console.log(4)
})
console.log(5)
//2 5 3 4 1

3

const first = () => (new Promise((resolve, reject) => {
  console.log(3)
  let p = new Promise((resolve, reject) => {
    console.log(7)
    setTimeout(() => {
      console.log(5)
      resolve(6)//会被忽略,因为状态已经改变过了,因为状态已经改变过了,因为状态已经改变过了!
    }, 0)
    resolve(1)
  })
  resolve(2)
  p.then((arg) => {
    console.log(arg)
  })
}))

first().then((arg) => {
  console.log(arg)
})
console.log(4)
//3 7 4 1 2 5

最先执行first(),先看它里面有无同步代码,所以先输出3,又因为里面的p也是同步执行的,所以7也是同步执行的(同2),接着打印4,接着启动定时器,将5放入宏任务(宏任务队列[5]),resolve(1)也是立即执行,意味着p的状态被改变了,p.then的回调函数先执行,将arg=1的放入微队列中(微任务队列[1]),然后执行resolve(2),将arg=2的放入微队列中(微任务队列[1,2]),然后执行微队列的任务,输出1,再输出2,再输出5

4

setTimeout(() => {
  console.log("0")
}, 0)
new Promise((resolve, reject) => {
  console.log("1")
  resolve()
}).then(() => {
  console.log("2")
  new Promise((resolve, reject) => {
    console.log("3")
    resolve()
  }).then(() => {
    console.log("4")
  }).then(() => {
    console.log("5")
  })
}).then(() => {
  console.log("6")
})

new Promise((resolve, reject) => {
  console.log("7")
  resolve()
}).then(() => {
  console.log("8")
})
//1 7 2 3 8 4 6 5 0

开启定时器,将console.log("0")放入宏队列,然后同步执行console.log("1"),再执行resolve(),将console.log("2")...console.log("5")放入微队列,然后立马执行console.log("7"),将console.log("8")放入微队列。

初始化代码执行结果//1 7 宏任务队列[0] 微任务队列[2,8]

取出console.log("2")执行,立即执行console.log("3"),再调用 resolve()console.log("4")进入微队列,虽然 console.log("5")不进入队列(console.log("4")还没有执行),但是函数已经有了结果,改变了状态,将console.log("6")放入微队列

执行结果//1 7 2 3 宏任务队列[0] 微任务队列[8,4,6]

取出console.log("8")执行,取出console.log("4")执行,将console.log("5")放入微队列,取出console.log("6")执行,取出console.log("5")执行,取出console.log("0")执行,