浏览器内核
浏览器进程: 主进程,主要负责页面管理以及管理其他进程的创建和销毁等,常驻的线程有:
- GUI渲染线程
- JS引擎线程
- 事件触发线程
- 定时器触发线程
- HTTP请求线程
GUI渲染线程
- 主要负责页面的渲染,解析HTML、CSS,构建DOM树,布局和绘制等。
- 当界面需要重绘或者由于某种操作引发回流时,将执行该线程。
- 该线程与JS引擎线程互斥,当执行JS引擎线程时,GUI渲染会被挂起,当任务队列空闲时,JS引擎才会去执行GUI渲染。
JS引擎线程
- 该线程当然是主要负责处理 JavaScript脚本,执行代码。
- 也是主要负责执行准备好待执行的事件,即定时器计数结束,或者异步请求成功并正确返回时,将依次进入任务队列,等待 JS引擎线程的执行 -该线程与 GUI渲染线程互斥,当 JS引擎线程执行 JavaScript脚本时间过长,将导致页面渲染的阻塞。
事件触发线程
- 主要负责将准备好的事件交给 JS引擎线程执行。
- 比如 setTimeout定时器计数结束, ajax等异步请求成功并触发回调函数,或者用户触发点击事件时,该线程会将整装待发的事件依次加入到任务队列的队尾,等待 JS引擎线程的执行。
定时器触发线程
- 主线程依次执行代码时,遇到定时器,会将定时器交给该线程处理,当计数完毕后,事件触发线程会将计数完毕后的事件加入到任务队列的尾部,等待JS引擎线程执行。
HTTP请求线程
- 负责执行异步请求一类的函数的线程,如: Promise,anxios,ajax等。
- 主线程依次执行代码时,遇到异步请求,会将函数交给该线程处理,当监听到状态码变更,如果有回调函数,事件触发线程会将回调函数加入到任务队列的尾部,等待JS引擎线程执行。
Render 进程 浏览器渲染进程(浏览器内核),主要负责页面的渲染、JS执行以及事件的循环。
Event Loop 是什么???
JavaScript的异步分为两种,宏任务(macro-task)和微任务(micro-task)
- 宏任务:包括整体代码script,setTimeout,setInterval
- 微任务:Promise.then(非new Promise),process.nextTick(node中)
执行机制:
- 从全局任务 script开始,任务依次进入栈中,同步任务被主线程执行,执行完后出栈。
- 遇到异步任务,交给异步处理模块处理,注册回调函数并放入事件队列里
- 等待调用栈为空时,事件队列里的回调函数依次进入栈中执行。
当异步任务进入栈执行时,是宏任务还是微任务呢?
- 由于执行代码入口都是全局任务 script,而全局任务属于宏任务,所以当栈为空,同步任务任务执行完毕时,会先执行微任务队列里的任务。
- 微任务队列里的任务全部执行完毕后,会读取宏任务队列中排最前的任务。
- 执行宏任务的过程中,遇到微任务,依次加入微任务队列。
- 栈空后,再次读取微任务队列里的任务,依次类推。
练手DEMO
setTimeout(function() {
console.log('setTimeout');
},1000)
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
1.setTimeout是个宏任务,放入宏任务队列中 2.new Promise 同步代码,立即执行console.log('promise'),然后看到微任务then,因此将其放入微任务的任务队列中 3.执行同步代码console.log('console') 4.主线程的宏任务,已经执行完毕,接下来要执行微任务,因此会执行Promise.then,到此,第一轮事件循环执行完毕 5.第二轮事件循环开始,先执行宏任务,即setTimeout的回调函数,然后查找是否有微任务,没有,时间循环结束
到此做个总结,事件循环,先执行宏任务,其中同步任务立即执行,异步任务,加载到对应的的Event Queue中(setTimeout等加入宏任务的Event Queue,Promise.then加入微任务的Event Queue),所有同步宏任务执行完毕后,如果发现微任务的Event Queue中有未执行的任务,会先执行其中的任务,这样算是完成了一次事件循环。接下来查看宏任务的Event Queue中是否有未执行的任务,有的话,就开始第二轮事件循环,依此类推。