1.浏览器的进程
1.1浏览器的渲染进程
包括GUI线程、JS引擎线程、定时器触发线程、事件触发线程、http异步请求线程。
js是单线程的脚本语言,也就是在一段时间内只能做事情。那么如何在一段时间内协调好事件、交互、样式、请求等行为,防止主线程阻塞,js的设计者就提出了event loop事件循环机制。
2.如何实现异步
上文所讲,js是一种单线程的脚本语言。那么单线程如何实现异步呢?先来了解几个基本概念。
2.1执行上下文
执行上下文包括全局执行上下文、函数执行上下文、eval函数执行上下文。
执行上下文的生命周期包括创建-执行-回收。执行上下文可看作栈,先进后出,后进先出。由于js代码运行时,最先进入的是全局执行上下文,因此处于栈底的永远是全局执行上下文,栈顶的是当前正在执行函数的执行上下文。
全局执行上下文:所有不在函数代码块中的代码,都位于全局执行上下文中。全局执行上下文只有一个,例如浏览器的执行上下文就是window对象,this指向这个全局对象。
函数执行上下文:顾名思义,处于函数体中。只有调用该函数时,才会为该函数创建一个新的执行上下文。函数执行上下文可以有无数个。
eval函数执行上下文:运行在eval函数中的代码,很少用。
执行上下文具体可看这位大佬的博文:amberzqx.com/2020/02/04/…
const firstFunction = () => {
console.log('1');
secondFunction();
console.log('2');
}
const secondFunction = () => {
console.log('3');
}
firstFunction();
console.log(4)
// 1324
//从上到下的执行
//从上到下执行,先是全局作用域,那就是栈底第一个
//firstFunction的调用,打印出1,现在栈顶是secondFunction,因为函数里面还没有执行完,所以还没有被销毁
//secondFunction的调用,打印3,secondFunction,因为函数里面执行完,所以要被销毁
//再执行栈顶firstFunction里面的2
//最后执行全局作用域中的4
2.2 js任务
同步任务,是指在主线程上排队执行的任务,只有上一个任务执行完毕,才会进行下一个任务;异步任务,是指不进入主线程,而进入任务队列中的任务。只有任务队列通知主线程,某个异步任务可以执行,该异步任务才会进入主线程中执行。
上述任务的解释,串起来讲,也就是event loop。具体见第三部分。
2.3宏任务和微任务
宏任务可以理解为,每次执行栈执行的代码就是一个宏任务,每个宏任务都是添加到任务队列中执行的。因此“任务队列”又称“宏任务队列”。常见的宏任务有:整体的script、setTimeOut、setTimeInterval、setImmediate
微任务是指当前宏任务执行完成后,立即执行的任务。常见的微任务有:Promise、process.nextTick
**! Caution:**Promise新建后立即执行,也就是说,new Promise构造函数的一个宏任务,但promise注册的.then回调和.catch回调函数是微任务。
**! Important:**每次事件循环,都是先执行宏任务,再执行宏任务代码块里面的微任务。也就是每个事件循环只会执行一个宏任务。
每次事件循环称为一个tick,每次tick先执行宏任务,当遇到宏任务中有微任务时,将微任务放入微任务队列中。宏任务执行完毕后,再依次去执行已被放入微任务队列中的微任务。如此循环。
(宏任务和微任务有很多代码执行的例子,例如下面这种,先打印出什么,再打印出什么 -.- 例子很多,可自行百度)
console.log('1')
setTimeOut(() => {
console.log('2')
}, 0)
Promise.resolve().then(() => {
console.log('3')
}).then(() => {
console.log('4')
})
console.log('5')
// 1 5 3 4 2
//第一轮循环,执行宏任务script里面的同步任务,遇到微任务挂起,先执行1、5
//执行完宏任务,执行微任务3、4 ,微任务执行完毕了就是下一轮事件循环的开始
//第二轮循环,执行setTimeOut里面的2
3.eventloop原理
event loop本质上是一种事件循环机制 。所有的同步任务都在主线程上执行,形成一个执行栈;主线程之外,还存在一个任务队列,只要异步任务有了运行结果,就由任务队列通知主线程,在主线程中放置一个事件;一旦执行栈中的所有同步任务都执行完毕,系统就开始读取任务队列钟会的异步任务,此时异步任务就可以结束等待状态,进入执行栈,开始执行;上述过程不断循环,就形成了event loop。