前言
事件循环是JavaScript中一个非常重要的概念,其解释了JavaScript代码在执行过程中处理各种事件和任务的机制。本文将简要讨论事件循环的机制,帮助读者更好地理解JavaScript中的异步编程。
JavaScript代码执行机制
首先要了解的就是JS的代码的执行机制,JavaScript是一门单线程的语言,单线程意味着 JavaScript 引擎同一个时间只能做一件事。
为什么 JavaScript 是单线程的?
关于这个问题可以看下阮一峰老师对于这个问题的解答:
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准? 所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。 ------JavaScript 运行机制详解:再谈Event Loop
单线程导致的问题
如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。 那么这个问题是如何解决的呢? 我们可以参考阮一峰老师文章中的这段话:
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM 。所以,这个新标准并没有改变JavaScript单线程的本质。 ------JavaScript 运行机制详解:再谈Event Loop
提炼下这段话的内容就是:HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程 。于是,JS 中出现了同步和异步。
同步和异步
首先来了解下同步和异步的概念
- 同步
- 前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。
- 异步
- 在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,还可以去处理其他事情。
JavaScript中的同步任务和异步任务
在JavaScript中也有着同步与异步的概念,他们分别对应着同步任务与异步任务这两个概念
同步任务
- 同步任务指的是在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
- 同步任务都在主线程上执行,形成一个 执行栈
异步任务
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。------JavaScript 运行机制详解:再谈Event Loop
如果浏览器识别到代码为异步任务,会这段代码放入到任务队列中暂时存放下来,等待同步任务执行完成后再执行异步任务队列中存放的代码,那么什么样的代码才会被浏览器识别为异步任务呢? 一般而言,我们可以将下面的代码视为异步代码:
- 常见的事件,如
click
、resize
等 - 资源加载,如
load
、error
等 - 定时器,包括 setInterval、setTimeout 等
当浏览器遇到以上的代码的时候就会将其视为异步任务。 ❕注:本文不会涉及到宏微任务相关的概念,后面会写一篇文章来整理这块的知识点,这里就用比较简单的方式来写,方便初学者理解
同步于异步任务的执行顺序
- 先执行执行栈中的同步任务。
- 如果遇到异步任务,交给对应的异步处理模块进行处理,处理好之后会将该任务先放入任务队列中。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面的第三步
事件循环
由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop) 。