不了解事件循环EventLoop的不是一个好前端er

零 JavaScript教程评论125字数 1845阅读6分9秒阅读模式

不了解事件循环EventLoop的不是一个好前端er

前言

JavaScript是单线程的脚本语言,意味着它一次只能执行一个任务。然而,现代Web应用常常需要处理异步操作,如网络请求、定时器等,为了让线程不阻塞,Event Loop出现了,它是JavaScript引擎管理异步操作的核心机制。

在Event Loop的学习之前,我们得先弄懂栈与队列这两种数据结构以及JavaScript中的宏任务与微任务文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

  • 栈(stack):一种先进后出的数据结构,就像一个桶,最先放的得最后才能拿出来。

image.png文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

  • 队列(queue):先进先出,就像一个只有一条道的隧道,先进去的车子先出来。

image.png文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

EventLoop

概述

EventLoop(事件循环)是编程中管理异步操作和非阻塞IO的一种重要机制,它的目的就是让程序可以在等待某些耗时操作(如网络请求、定时器等)完成的同时,能够执行其他任务,从而避免程序阻塞。换句话说,我在等咖啡的同时EventLoop让我可以边写文章而不是发呆坐在那。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

图解

Event Loop的大概流程:文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

image.png文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

任务在要被执行时会被分为同步和异步任务,同步任务正常执行,如果是异步任务就先放进Event Table中,比如在执行时碰到了一个定时器settimeout,它就会被放入Table中,同时定时器开始计时,当时间结束时它进入Event Queue,在这里面满足先进先出的原则,先来的就会更早来到主线程运行,这样我们的异步任务就不会阻塞我们的同步任务了。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

宏任务与微任务

JavaScript中任务被分为两种,一种叫宏任务,一种叫微任务,它们在Event Loop机制中也扮演着至关重要的角色,与各种异步任务的执行顺序息息相关文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

  • 宏任务(Macro Task)
  1. 整个script
  2. 定时器任务,如setTimeoutsetInterval
  3. 浏览器事件,如clickmouseover
  4. 网络请求,如fetchXMLHttpRequest
  5. UI渲染,如重绘。
  • 微任务(Micro Task)
  1. Promise的回调函数
  2. Async/Await 函数
  3. MutationObserver的回调函数
  4. process.nextTick Node.js环境下

执行顺序

先执行整个script这个宏任务,其中会包含各种小的宏任务以及微任务,从上至下,碰到同步任务就执行,碰到宏任务先放进宏任务队列,碰到微任务就放到微任务队列,当script这个宏任务执行到底时,就开始执行微任务队列里面的任务,执行完里面的微任务后去宏任务队列拿一个任务出来,如果这个宏任务里面又有许多微任务那就照样放进微任务队列,等待这个宏任务执行完后再执行微任务队列中的任务。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

总结一下:最开始执行的一定是宏任务,然后这个宏任务中的微任务会先于其中的宏任务执行。文章源自灵鲨社区-https://www.0s52.com/bcjc/javascriptjc/17087.html

说再多都不如来个例子

js

代码解读
复制代码
console.log("Start");       // 同步任务
setTimeout(() => {          // 宏任务
  console.log("In Timeout");
  setTimeout(() => {           // 宏任务
    console.log("timeover");
  })
  Promise.resolve().then(function() {    // 微任务
    console.log('promise2');
  });
});
Promise.resolve().then(function() {     // 微任务
    console.log('promise1');
  });
console.log("End");     // 同步任务

输出:

image.png

解析(从上往下):

  1. 同步任务先执行,毋容置疑,Start直接输出。
  2. 将第一个settimeout(第2行)放入宏任务队列。
  3. 把promise(第11行)放入微任务队列。
  4. 输出End
  5. 整个script这个宏任务执行完毕,检查微任务队列,发现promise(第11行),执行输出promise1
  6. 微任务队列清空,执行下一个宏任务settimeout(第2行),同步任务直接输出In Timeout
  7. 将settimeout(第4行)放入宏任务队列。
  8. 把promise(第7行)放入微任务队列。
  9. settimeout(第2行)这个宏任务执行完毕,检查微任务队列,发现promise(第7行),执行输出promise2
  10. 微任务队列清空,执行下一个宏任务settimeout(第4行),输出timeover

通过例子结合概念理解事半功倍。

结语

想要成为一个好的前端er,Event Loop是核心,它关乎着各项任务的执行顺序,同时也是面试官常考的知识点。不仅要了解这个机制,我们也要正确地分清宏任务与微任务。

零
  • 转载请务必保留本文链接:https://www.0s52.com/bcjc/javascriptjc/17087.html
    本社区资源仅供用于学习和交流,请勿用于商业用途
    未经允许不得进行转载/复制/分享

发表评论