浏览器中的js执行机制
今天在网上看到讨论浏览器的工作原理,我发现学习前端这么久了,竟然没有系统的学习过浏览器,知道的都是些零零散散的东西,于是趁现在空余时间,赶紧瞅瞅。
单线程的含义
什么是线程?什么是进程?
进程包含多个线程,进程是操作系统最小的执行单位。
浏览器是一个多进程(multi-process),一个浏览器只有一个主进程(Browser Process)负责管理Tabs(窗口),协调Renderer Process 和其他Process
渲染进程(Renderer Process)是一个多线程的 它的主线程负责渲染页面和执行js以及事件循环 渲染进程的主线程是一个单线程(同一时间js执行线程和ui渲染线程只有一个在主线程上)
同步、异步
正是因为js是单线程的,很多的任务只能一个一个排队执行这对用户体验不好,所以就将任务分成了同步任务和异步任务。
简单的理解:
-
同步:获取元素、console.log()、alert、定义 变量…
-
异步: 事件、定时器、延时器 …
- 判断任务是同步还是异步
- 同步任务直接在主线程执行、异步任务进入事件表并等待一个条件(时间,或者用户操作:例如 点击)。
- 注册回调函数 异步任务进入事件队列
- 当主线程空闲时(同步执行完成),事件队列中的任务才被推入主线程执行。
完了吗?事情并非如此
console.log('1');
setTimeout(function() {
console.log('第一个setTimeout');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('第一个setTimeout内的promise');
resolve();
}).then(function() {
console.log('第一个setTimeout内的promise的then')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('第二个setTimeout');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('第二个setTimeout的promise');
resolve();
}).then(function() {
console.log('第二个setTimeout的promise的then')
})
})
其运行结果如下
实际上运行的结果并不符合咱们同步异步分类
所以执行的机制是怎样的?(宏任务、微任务)
我们对任务有了更加精细的分类
- macro-task(宏任务):包括整体代码script,setTimeout,setInterval
- micro-task(微任务):Promise,process.nextTick
进入整体代码(宏任务)后开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务.并且也要按照同步异步一起嵌套着来。
对照以上代码,其执行顺序为
//A.先执行同步代码
//1.执行宏任务(整段script代码)
console.log('1')
//2.执行微任务(promise)
console.log('7');
//3.执行微任务process.nextTick
//Node执行完所有同步任务才执行process.nextTick的任务队列
console.log('6');
//4. 执行异步代码 promise的then方法
console.log('8')
//B.执行异步代码
//1.执行第一个定时器中的宏任务
console.log('第一个setTimeout')
//2.执行第一个定时器中的微任务
console.log('第一个setTimeout内的promise')
//3.执行第二个定时器中的宏任务
console.log('第二个setTimeout')
//4.执行第二个定时器中的微任务
console.log('第二个setTimeout内的promise')
//5.当所有的同步任务执行后执行process.nextTick
//第一个定时器中的process.nextTick
console.log('3');
//第二个定时器中的process.nextTick
console.log('10');
//6.执行异步then函数
//先执行第一个定时器中的
console.log('第一个setTimeout内的promise的then')
//先执行第二个定时器中的
console.log('第二个setTimeout内的promise的then')
个人理解:
1.先执行同步宏任务,再执行同步微任务,其次是异步微任务
2.执行异步宏任务,再执行同步微任务,其次是异步微任务