在这之前,我们得先简单了解下浏览器的进程和线程。
1. 什么是进程?
程序运行需要自己的空间,我们可以简单的把运行程序的内存空间理解为进程。每个应用都至少有一个进程,进程之间是相互独立的,即使需要通信,也需要双方同意才行。
2. 什么是线程?
有了进程之后就可以运行程序的代码了,可以将运行代码的一条通道理解为线程,一个进程至少需要有一条线程。
在浏览器中有许多的进程,例如: 网络进程、浏览器进程、渲染进程等等,这里主要讲的是渲染进程,当渲染进程启动之后会自动开启一个渲染主进程,前端的HTML、CSS、JS、布局等等都是运行在渲染主进程之中。
渲染主进程每次只会运行一个任务,当当前任务执行完毕之后会从消息队列取下一个任务执行,这也是js为单线程执行的原因。
而实际上消息队列中也细分为了很多其他的队列,这里简单列举几个:
这些任务队列之中,执行优先级最高的是微任务队列,当渲染主进程任务执行完毕之后会优先从微任务队列调度任务继续执行,没有则再从其他队列调度,在chrome浏览器中,交互队列的优先级是高于延时队列的,当然每个浏览的规则可能是不一样的,这也是W3C标准所允许的。当然毋庸置疑在任何浏览器中微任务队列的优先级都是最高的。
渲染主线程的执行顺序为: 首先从上往下执行js代码,有微任务则将该回调事件放置到微任务队列,有延时任务则将该回调事件放置到延时任务队列,当主线程任务执行完毕之后,会去查看微任务队列时候有任务,有则执行,没有则查看交互队列,延时队列...每次主线程执行完毕之后都会循环查看微任务以及其他任务队列,直到所有队列中的任务都执行完毕。这就是浏览器的事件循环机制(EventLoop)。
我们常见的微任务事件: Promise.then()...., 延时任务: setTiemout....
接下来有一道简单的练习题目:
console.log(3)
setTimeout(() => {
console.log(1)
Promise.resolve(2).then((res) => {
console.log(res)
setTimeout(() => {
console.log(5)
})
})
})
console.log(4)
最后的执行结果为: 34125