zhangdizhangdi

事件循环

学习与参考

宏任务、微任务

JS 主线程不断的循环往复的从任务队列中读取任务,执行任务,这种运行机制称为事件循环(event loop)。

宏任务

  • script (可以理解为外层同步代码)
  • setTimeout、setInterval
  • postMessage、MessageChannel(浏览器)
  • UI rendering/UI交互事件(浏览器)
  • setImmediate、I/O(Node.js)

微任务

  • Promise.then/catch/finally
  • MutaionObserver(浏览器)
  • process.nextTick(Node.js)

运行机制

  • 执行一个宏任务(栈中没有就从事件队列中获取)
  • 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

输出题

基础

js
const promise1 = new Promise((resolve, reject) => {
  console.log('promise1')
  resolve('resolve1')
})
const promise2 = promise1.then(res => {
  console.log(res)
})
console.log('1', promise1)
console.log('2', promise2)

/**
'promise1'
'1' Promise{<resolved>: 'resolve1'}
'2' Promise{<pending>}
'resolve1'
*/

then、catch、finally

js
setTimeout(() => console.log('a'), 0)
var p = new Promise(resolve => {
  console.log('b')
  resolve()
})
p.then(() => console.log('c'))
p.then(() => console.log('d'))
console.log('e')
// b e c d a
js
const promise = new Promise((resolve, reject) => {
  reject('error')
  resolve('success2')
})
promise
  .then(res => {
    console.log('then1: ', res)
  })
  .then(res => {
    console.log('then2: ', res)
  })
  .catch(err => {
    console.log('catch: ', err)
  })
  .then(res => {
    console.log('then3: ', res)
  })
/**
"catch: ", "error"
"then3: ", undefined
 */
js
const p1 = new Promise(resolve => {
  setTimeout(() => {
    resolve('resolve3')
    console.log('timer1')
  }, 0)
  resolve('resovle1')
  resolve('resolve2')
})
  .then(res => {
    console.log(res)
    setTimeout(() => {
      console.log(p1)
    }, 1000)
  })
  .finally(res => {
    console.log('finally', res)
  })

/**
"resovle1"
"finally", undefined
"timer1"
Promise {<fulfilled>: undefined}
*/
js
Promise.resolve()
  .then(() => {
    return new Error('error!!!')
  })
  .then(res => {
    console.log('then: ', res)
  })
  .catch(err => {
    console.log('catch: ', err)
  })

// then:  Error: error!!!
js
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)

// 1
js
new Promise((resolve, reject) => {
  console.log('B')
  resolve() // 1
})
  .then(() => {
    // 第一个 then
    console.log('C')
    new Promise((resolve, reject) => {
      resolve() // 2
    })
      .then(() => {
        console.log('D')
      })
      .then(() => {
        // 3
        console.log('E')
      })
  })
  .then(() => {
    // 第二个 then 加入
    console.log('F')
  })

//B C D F E
js
// - [说说下面代码的输出结果](https://fe.ecool.fun/topic/b42993a0-daf4-47df-b933-2fbded17cdff)

Promise.resolve()
  .then(() => {
    console.log(0)
    return Promise.resolve(4)
  })
  .then(res => {
    console.log(res)
  })

/**
 * 相当于
 
Promise.resolve().then(() => {
    console.log(0);
    return 4;
})
.then()
.then()
.then((res) => {
    console.log(res)
})

 */

Promise.resolve()
  .then(() => {
    console.log(1)
  })
  .then(() => {
    console.log(2)
  })
  .then(() => {
    console.log(3)
  })
  .then(() => {
    console.log(5)
  })
  .then(() => {
    console.log(6)
  })

// 0 1 2 3 4 5 6
js
Promise.resolve()
  .then(
    function success(res) {
      throw new Error('error!!!')
    },
    function fail1(err) {
      console.log('fail1', err)
    },
  )
  .catch(function fail2(err) {
    console.log('fail2', err)
  })

// fail2 Error: error!!!
js
Promise.resolve('1')
  .then(res => {
    console.log(res)
  })
  .finally(() => {
    console.log('finally')
  })
Promise.resolve('2')
  .finally(() => {
    console.log('finally2')
    return '我是finally2返回的值'
  })
  .then(res => {
    console.log('finally2后面的then函数', res)
  })

/**
"1"
"finally2"
"finally"
"finally2后面的then函数", "2"
*/
js
Promise.reject('err!!!')
  .then(
    res => {
      console.log('success', res)
    },
    err => {
      console.log('error', err)
    },
  )
  .catch(err => {
    console.log('catch', err) // !没走到这里
  })

// error err!!!

setTimeout

js
setTimeout(() => {
  console.log('timer1')
  setTimeout(() => {
    console.log('timer3')
  }, 0)
}, 0)
setTimeout(() => {
  console.log('timer2')
}, 0)
console.log('start')
/**
start
timer1
timer2
timer3
 */

setTimeout(() => {
  console.log('timer1')
  Promise.resolve().then(() => {
    console.log('promise')
  })
}, 0)
setTimeout(() => {
  console.log('timer2')
}, 0)
console.log('start')

/**
start
timer1
promise
timer
 */
js
const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => {
  throw new Error('error!!!')
})
console.log('promise1', promise1)
console.log('promise2', promise2)
setTimeout(() => {
  console.log('promise1 2000', promise1)
  console.log('promise2 2000', promise2)
}, 2000)

/**
 promise1 Promise {<pending>}
 promise2 Promise {<pending>}
 Uncaught (in promise) Error: error!!!
 promise1 2000 Promise {<fulfilled>: 'success'}
 promise2 2000 Promise {<rejected>: Error: error!!!}
 */

all、race

js
function runAsync(x) {
  const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))
  return p
}
function runReject(x) {
  const p = new Promise((res, rej) =>
    setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x),
  )
  return p
}
Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])
  .then(res => console.log('then', res))
  .catch(err => console.log('err', err))

/**
1
3
2
"catch err", "Error: 2"
4
*/

async、await

js
async function async1() {
  await async2()
  console.log('async1')
  return 'async1 success'
}
async function async2() {
  return new Promise((resolve, reject) => {
    console.log('async2')
    reject('error')
  })
}
async1().then(res => console.log(res))

/**
async2
Uncaught (in promise) error
*/
js
async function async1() {
  try {
    await Promise.reject('error!!!')
  } catch (e) {
    console.log(e)
  }
  console.log('async1')
  return Promise.resolve('async1 success')
}
async1().then(res => console.log(res))
console.log('script start')

/**
"script start"
"error!!!"
"async1"
"async1 success"
*/
js
async function async1() {
  console.log('async1 start')
  await new Promise(resolve => {
    console.log('promise1')
  })
  console.log('async1 success')
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res => console.log(res))
console.log('srcipt end')

/**
"srcipt start"
"async1 start"
"promise1"
"srcipt end"
 */

/**
在async1中await后面的Promise是没有返回值的,也就是它的状态始终是pending状态,因此相当于一直在await,await,await却始终没有响应...   
所以在await之后的内容是不会执行的,也包括async1后面的 .then。
 */

async function async1() {
  console.log('async1 start')
  await new Promise(resolve => {
    console.log('promise1')
    resolve('promise resolve')
  })
  console.log('async1 success')
  return 'async1 end'
}
console.log('srcipt start')
async1().then(res => {
  console.log(res)
})
new Promise(resolve => {
  console.log('promise2')
  setTimeout(() => {
    console.log('timer')
  })
})

/**
"srcipt start"
"async1 start"
"promise1"
"promise2"
"async1 success"
"async1 end"
"timer"
*/
js
const myPromise = Promise.resolve(Promise.resolve('Promise!'))

function funcOne() {
  myPromise
    .then(res => {
      console.log('11', res)
      return res
    })
    .then(res => console.log('12', res))
  setTimeout(() => console.log('1 Timeout!'), 0)
  console.log('1 Last line!')
}

async function funcTwo() {
  const res = await myPromise
  console.log('2', await res) //去掉await 结果又不一样
  setTimeout(() => console.log('2 Timeout!'), 0)
  console.log('2 Last line!')
}

funcOne()
funcTwo()
js
// 参考 [我们需要知道的 JS 异步编程](https://juejin.cn/post/6950785975693869069) 思考题与练习(字节)

async function async1() {
  await async2()
  console.log('async1 end')
}
async function async2() {
  return new Promise((resolve, reject) => {
    resolve()
    console.log('async2 promise')
  })
}
async1()
new Promise(function (resolve) {
  console.log('promise1')
  resolve()
})
  .then(function () {
    console.log('promise2')
  })
  .then(function () {
    console.log('promise3')
  })
  .then(function () {
    console.log('promise4')
  })

//async2 promise
//promise1
//promise2
//promise3
//async1 end
//promise4

// !!! 与上面的区别
async function async1() {
  await async2()
  console.log('async1 end')
}
function async2() {
  return new Promise((resolve, reject) => {
    resolve()
    console.log('async2 promise')
  })
}
async1()
new Promise(function (resolve) {
  console.log('promise1')
  resolve()
})
  .then(function () {
    console.log('promise2')
  })
  .then(function () {
    console.log('promise3')
  })
  .then(function () {
    console.log('promise4')
  })

//async2 promise
//promise1
//async1 end
//promise2
//promise3
//promise4

async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
  return 'async return'
}

async function async2() {
  console.log('async2')
}

console.log('script start')

setTimeout(function () {
  console.log('setTimeout')
}, 0)

async1().then(function (message) {
  console.log(message)
})

new Promise(function (resolve) {
  console.log('promise1')
  resolve()
}).then(function () {
  console.log('promise2')
})

console.log('script end')

//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//async return
//setTimeout

综合

js
const first = () =>
  new Promise((resolve, reject) => {
    console.log(3)
    let p = new Promise((resolve, reject) => {
      console.log(7)
      setTimeout(() => {
        console.log(5)
        resolve(6)
        console.log(p)
      }, 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
Promise {<fulfilled>: 1}
*/
js
var p = new Promise((res, rej) => {
  res('hello one')
  console.log('good morning')
})

function hello() {
  console.log('hello begins')
  return p
}

hello()
  .then(res => {
    console.log(res)
    console.log('hello1111111111')
    return 'hello two'
  })
  .then(res => {
    console.log(res)
    console.log('hello22222222222')
    return 'hello three'
  })
  .then(res => {
    console.log(res)
    console.log('hello33333333333')
  })

function test1() {
  console.log('test1')
}

async function asy() {
  console.log('asy begins')
  await console.log('asy---111111')

  console.log('async1')
  await console.log('asy---222222')

  console.log('asy ends')
}

asy()

test1()

function* gnrt() {
  console.log(1)
  yield console.log(11111111)

  console.log(2)
  yield console.log(22222222)

  console.log(3)
  yield console.log(33333333)
}

var result = gnrt()
result.next()
result.next()
result.next()

/*
good morning
hello begins
asy begins
asy---111111
test1
1
11111111
2
22222222
3
33333333
hello one
hello1111111111
async1
asy---222222
hello two
hello22222222222
asy ends
hello three
*/
js
console.log('start')
setTimeout(() => {
  console.log('setTimeout')
}, 0)
new Promise(() => {
  let chain = Promise.resolve()
  chain.then(() => console.log('chain1'))
  chain.then(() => console.log('chain2'))
  chain.then(() => console.log('chain3'))
})
let chain = Promise.resolve()
chain.then(() => console.log('chain4'))
console.log('end')
/*
start
end
chain1
chain2
chain3
chain4
setTimeout
*/

/*!!!注意区别*/
console.log('start')
setTimeout(() => {
  console.log('setTimeout')
}, 0)
new Promise(() => {
  let chain = Promise.resolve()
  chain
    .then(() => console.log('chain1'))
    .then(() => console.log('chain2'))
    .then(() => console.log('chain3'))
})
let chain4 = Promise.resolve()
chain4.then(() => console.log('chain4'))
console.log('end')
/*
start
end
chain1
chain4
chain2
chain3
setTimeout
*/