进程: 一个程序(浏览器打开一个页面就是开辟一个进程)
线程: 程序中具体做事情的
一个进程中会包含一个或多个线程
浏览器是多线程的
包括:
- GUI渲染线程:用于渲染页面
- JS引擎线程:用于渲染和解析JS
- 事件触发线程:监听DOM事件触发
- 定时器触发线程:监听定时器是否到时间
- 异步HTTP请求线程:从服务器端获取资源/数据的
- WebWorker
- ……
利用多线程是可以实现“异步编程”的:同时做多件事情
“同步编程”:单线程,一次只能处理一件事情,这件事情完成,才能继续处理后面的事情
JS是单线程的
JS是单线程的,因为浏览器只会分配一个“JS引擎线程”去渲染JS
- JS中大部分操作都是同步的
- 但是JS中也一定会有一些异步的操作代码
JS中执行异步操作的过程
JS引擎中分为主线程(ECStack)和WebAPI任务监听队列(监听异步任务是否可以执行),代码在主线程中按顺序执行,当遇到异步任务时,将任务加入到WebAPI中进行监听,如果监听到异步任务可以执行时,将异步任务加入到EventQueue(任务等待队列)中。
EventQueue分为“微任务”和“宏任务”两个部分,相应的任务加入到相应的队列中。
JS中的微任务:
- requestAnimationFrame(有争议)
- Promise.then/catch/finally
- async/await
- queueMicrotask
- process.nextTick[node]
- Mutation.Observer
- IntersectionObserver
- ……
JS中的宏任务:
- setTimeout/setInterval
- 事件绑定/队列
- XMLHttpRequest/Fetch
- MessageChannel
- script整体代码块
- ……
在EventQueue中,先执行微任务,再执行宏任务,谁先到的先执行谁。执行时,将要执行的任务放到主线程中去执行,这一次的拿出来的代码执行结束,再去EventQueue中查找,这个过程叫做EventLoop
EventLoop事件循环机制:
- 等待同步代码执行,然后去EventQueue任务队列中找异步任务执行
- 先找可执行的异步微任务,如果有,永远都要先执行微任务,再执行宏任务
- 同样类型的任务,谁先进入队列的,就优先执行谁
举例:
setTimeout(() => {
console.log(1);
}, 20);
console.log(2);
setTimeout(() => {
console.log(3);
}, 10);
console.log(4);
// console.time('AA');
for (let i = 0; i < 90000000; i++) {
// do soming
}
// console.timeEnd('AA'); //=>AA: 79ms 左右
console.log(5);
setTimeout(() => {
console.log(6);
}, 8);
console.log(7);
setTimeout(() => {
console.log(8);
}, 15);
console.log(9);