js事件循环详解

x33g5p2x  于2022-02-28 转载在 其他  
字(3.3k)|赞(0)|评价(0)|浏览(371)

在js事件循环中,我们需要区分环境,因为javascript可以在node环境和浏览器环境下运行的。所以我们总结js事件循环也从这两个方面去总结。

一、浏览器中js线程

浏览器是一个进程吗?它里面只有一个线程吗?
目前多数的浏览器其实是多进程的,当我们打开一个tab页面时就会开启一个新的进程,这是为了防止一个页面卡死而造成所有页面无法响应。每一个进程中又存在很多的线程,其中包括执行JavaScript代码的线程。
JavaScript的代码执行是在一个单独的线程中执行的,这也就意味着javascript的代码,在同一时刻只能做一件事,如果这个事情比较耗时的话,就意味着当前线程就会被阻塞。
所以真正耗时的操作,实际上并不是由JavaScript线程来执行的,浏览器的每一个进程是多线程的,那么其他线程可以来完成这个耗时的操作,比如网络请求,定时器,我们只需要在特定的时候执行应该有的回调即可。

二、浏览器的事件循环

上面代码执行过程如下所示:

因为在执行js代码时,会创建一个新的JavaScript线程,如果遇到定时器等异步操作时,会将该任务交给浏览器的其他线程去执行,当执行完成后,将其回调函数放入任务队列中。js在执行完主线程中的任务后,会从任务队列中提取任务来执行。

三、浏览器中的微任务和宏任务

1、宏任务有:
setTimeOut,setInternal,DOM监听,UI rendering, ajax等。
2、微任务有:
Promise.then的回调Mutation Observer ApIqueueMicrotask等。
3、执行流程
1、首先先执行主程序中的代码
2、然后在执行宏任务队列的代码之前,要先看看微任务队列中是否为空,如果不为空,则将微任务队列中的任务取出执行。
3、在执行宏任务之前,保证微任务队列中的任务为空。

四、浏览器中的事件循环面试题

  1. setTimeout(function () {
  2. console.log("setTimeOut1") //六
  3. new Promise(function (resolve) {
  4. resolve()
  5. }).then(function () {
  6. new Promise(function (resolve) {
  7. resolve()
  8. }).then(function () {
  9. console.log("then4") //八
  10. })
  11. console.log("then2") //七
  12. })
  13. })
  14. new Promise(function (resolve) {
  15. console.log("promise1") //一
  16. resolve()
  17. }).then(function () {
  18. console.log("then1") //三
  19. })
  20. setTimeout(function () {
  21. console.log("setTimeOut2") //九
  22. })
  23. console.log(2) //二
  24. queueMicrotask(() => {
  25. console.log("queueMicrotask1") //四
  26. })
  27. new Promise(function (resolve) {
  28. resolve()
  29. }).then(function () {
  30. console.log("then3") //五
  31. })
  32. /*
  33. promise1
  34. 2
  35. then1
  36. queueMicrotask1
  37. then3
  38. setTimeOut1
  39. then2
  40. then4
  41. setTimeOut2
  42. */
  1. async function async1() {
  2. console.log("async1 start") //二
  3. await async2()
  4. console.log("async1 end") //六
  5. }
  6. async function async2() {
  7. console.log("async2") //三
  8. }
  9. console.log("script start") //一
  10. setTimeout(function () {
  11. console.log("setTimeOut") //八
  12. }, 0)
  13. async1()
  14. new Promise(function (resolve) {
  15. console.log("promise1") //四
  16. resolve()
  17. }).then(function () {
  18. console.log("promise2") //七
  19. })
  20. console.log("script end") //五
  21. /*
  22. script start
  23. async1 start
  24. async2
  25. promise1
  26. script end
  27. async1 end
  28. promise2
  29. setTimeOut
  30. */

五、node事件循环

如上图所示,在node环境中通过libuv维护一个事件队列和事件循环,并且通过其中也存在线程池,通过不断轮询线程池中的任务,并将其放入事件队列中,最终再执行线程池中的任务。

六、node事件循环的图解

七、node中的微任务和宏任务

1、微任务:
next tick queue: process.nexttick
other queue: Promise的then回调函数,queueMicrotask
2、宏任务
timer queue:setTimeOut, setInternal
poll queue: I / O事件
check queue: setImmediate
close queue: close事件
3、在node中执行的顺序

  1. 1next tick microtask queue
  2. 2other microtask queue
  3. 3timer queue
  4. 4poll queue
  5. 5check queue
  6. 6close queue

八、node事件循环面试题

  1. async function async1() {
  2. console.log("async1 start") // 2
  3. await async2()
  4. console.log("async1 end") // 9
  5. }
  6. async function async2() {
  7. console.log("async2") // 3
  8. }
  9. console.log("script start") // 1
  10. setTimeout(function () {
  11. console.log("setTimeOut0") // 11
  12. }, 0)
  13. setTimeout(function () {
  14. console.log("setTimeOut2") // 13
  15. }, 300)
  16. setImmediate(() => {
  17. console.log("setImmediate") // 12
  18. })
  19. process.nextTick(() => console.log("nextTick1")) // 7
  20. async1()
  21. process.nextTick(() => console.log("nextTick2")) // 8
  22. new Promise(function (resolve) {
  23. console.log("promise1") // 4
  24. resolve()
  25. console.log("promise2") // 5
  26. }).then(function () {
  27. console.log("promise3") // 10
  28. })
  29. console.log("script end") // 6
  30. /*
  31. script start
  32. async1 start
  33. async2
  34. promise1
  35. promise2
  36. script end
  37. nextTick1
  38. nextTick2
  39. async1 end
  40. promise3
  41. setTimeOut0
  42. setImmediate
  43. setTimeOut2
  44. */

相关文章