线程
javascript是一门单线程语言,是由前期网页需求而造成的,主要用途是负责与页面的交互,以及操作DOM(添加,删除等)。单线程在同一时间只能做一件事,这意味着,当有多个任务时,这些任务需要排队,前一个任务完成后才能继续下一个任务。
- ”JS是单线程的”指的是JS 引擎线程。
- 在浏览器环境中,有JS 引擎线程和渲染线程,且两个线程互斥。
Node环境中,只有JS 线程。
同步任务和异步任务
同步任务 是指在主线程上排队的任务,只有前面的任务执行完毕,才能执行当前线程后面的任务。它是在同一个线程进行下去的,需要根据先后顺序执行。
异步任务 是指不进入主线程,进入任务队列的任务。只要异步任务有了运行结果,就在任务队列之中放置一个事件。
(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件。
(3)一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到主线程(可执行栈)中,开始执行。
(4)主线程不断的重复上面的第三步
Event Loop
JS引擎常驻于内存中,等待宿主将JS代码或函数传递给它。也就是等待宿主环境分配宏观任务,反复等待 - 执行即为事件循环。
Event Loop中,每一次循环称为tick,每一次tick的任务如下:
- 执行栈选择最先进入队列的宏任务(一般都是
script),执行其同步代码直至结束; - 检查是否存在微任务,有则会执行至微任务队列为空;
- 如果宿主为浏览器,可能会渲染页面(更新
render); - 开始下一轮
tick,执行宏任务中的异步代码。
宏任务和微任务
宏任务是由宿主(JS运行的环境,一般为浏览器或者Node)发起的,而微任务由JavaScript自身发起。
宏任务(macrotask) | 微任务(microtask) | |
|---|---|---|
| 谁发起的 | 宿主(Node、浏览器) | JS引擎 |
| 具体事件 | 1. script (可以理解为外层同步代码) | 1. Promise |
2. setTimeout/setInterval | 2.MutaionObserver | |
3. UI rendering/UI事件 | 3. Object.observe(已废弃;Proxy 对象替代) | |
4. postMessage,MessageChannel | 4. process.nextTick(Node.js) | |
5. setImmediate,I/O(Node.js) | ||
| 谁先运行 | 后运行 | 先运行 |
会触发新一轮Tick吗 | 会 | 不会 |
- 在当前的微任务没有执行完成时,是不会执行下一个宏任务的。
- 所有会进入的异步都是指的事件回调中的那部分代码