JavaScript 事件循环机制(Event Loop)简述
单线程的 JavaScript
JavaScript 是浏览器的脚本语言。其主要作用是与客户端进行交互。最开始设计之初它就是单线程。因为它主要操作 DOM。如果设计成多线程,假设一个线程在操作某个 DOM 节点,一个线程又在删除这个 DOM 节点。这时候浏览器就无法判断以哪个线程为主,这种复杂的场景大大增加了语言的难度。所以 JavaScript 从一诞生就是单线程。也是它最重要的特性之一。
任务队列
因为 JavaScript 是单线程,所以所有的任务只能一个个等着被执行。如果一个任务是被 CPU 一直占着倒也罢。但是有时候是 IO (输入输出设备)占用的时间比较长,而 CPU 处在空闲状态。那么为了有效利用 CPU。可以将 IO 设备耗时较长的任务挂起,先执行后面的任务。等到 IO 设备返回了结果,再回过头来执行挂起的任务。任务队列是一个先进先出的结构,排在前面的事件,优先进入主线程被执行。
运行机制
- 所有的任务都在主线程执行,形成执行栈。
- 主线程之外,还有一个任务队列。系统将异步任务放在任务队列中。
- 等到主线程中的任务执行完成,系统就会读取任务队列中的任务。
- 异步任务结束了等待状态,就会从任务队列进入执行栈,恢复执行。
- 主线程重复以上步骤。
事件回调
除了常见的 IO 设备之外,用户交互(点击,滑动,触摸等)都会被添加到任务队列,等待主线程读取。IO 设备完成一项任务,就是在 “任务队列”中添加一个事件。表示相关的任务可以进入执行栈了。主线程读取任务队列,就是读取里面有哪些回调事件。
回调函数就是被任务队列挂起的代码。异步任务必须指定回调函数。当异步任务从任务队列中回到执行栈,就是回调函数被执行的时候。
事件循环(Event Loop)
主线程运行的时候,会产生堆和栈。栈中的代码会调用各种外部 API。他们在任务队列中加入各种事件。只要栈中的代码执行完毕,主线程就会去读取“任务列队”,依次执行哪些事件所对应的回调函数。主线程从“任务队列”中读取事件,这个过程是循环不断的。所以叫事件循环机制。