# JavaScript 运行机制
# 单线程
JavaScript语言的一大特色就是单线程。
使用多线程可以提高效率,为什么不用多线程? 提供一个场景:如果为多线程,一个线程添加DOM,一个线程删除DOM,浏览器以哪个线程为准? 为了避免问题复杂化,单线程是JS的核心。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JS创建多个线程,分为主线程与子线程,子线程完全由主线程控制,且不可以操作DOM,所以JS本质上还是单线程。
# 任务队列
在线程中执行一个一个的任务,是一个宏概念。
栈与队列:
- 栈:先入后出的数据结构。
- 队列:先入先出的数据结构。
JS任务分为两种:
- 同步任务:在执行栈中执行的任务。
- 异步任务:不进入主线程,放入任务队列的任务。
任务的执行流程:
- 在主线程上执行同步任务,形成执行栈。
- 如果检索到是异步任务,在任务队列中放置一个事件等待,挂起其回调函数。
- 执行完执行栈中全部的同步任务(此时空闲),系统开始按照队列上事件的排列顺序(先入先出)一个个读取,放入执行栈执行(执行其对应的回调函数)。
- 主线程不断重复上三步。
- 只要主线程空了(空闲了),就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
- 但是,由于存在后文提到的"定时器"功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。
- 异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。
定时器异步任务 setTimeout()
与setInterval()
,第二个参数为延时执行事件。
- 不管延时设置多低必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数
- HTML5规定第二个参数最低4毫秒,低于自动加到这个值。
- 要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在指定的时间执行。
# Event Loop
主线程清空后总会去"任务队列"中读取事件,不断循环,整个运行机制称为Event Loop(事件循环)。

- 主线程运行时,产生堆栈。
- 栈中执行时,遇到需要异步的代码,栈中代码调用API,在任务队列中加入各种事件。
- 执行完栈中代码(空闲了),主线程读取任务队列,依次执行那些事件对应回调函数。