网页的本质就是超级文本标记语言,通过结合使用其他的Web技术(如:脚本语言、公共网关接口、组件等),可以创造出功能强大的网页。因而,超级文本标记语言是万维网(Web)编程的基础,也就是说万维网是建立在超文本基础之上的。超级文本标记语言之所以称为超文本标记语言,是因为文本中包含了所谓“超级链接”点。
本篇文章给大家带来的内容是关于浏览器事件循环的深入了解(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
浏览器的事件循环,前端再熟悉不过了,每天都会接触的东西。但我以前一直都是死记硬背:事件任务队列分为macrotask和microtask,浏览器先从macrotask取出一个任务执行,再执行microtask内的所有任务,接着又去macrotask取出一个任务执行...,这样一直循环下去。但是对于下面的代码,我一直懵逼,setTimeout属于macrotask,按照上面的规则,setTimeout应该先被取出来执行啊,但是我却被执行结果打脸了。
<script>
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
})
// 我曾经的预期是:2 1 3
// 实际输出:2 3 1
</script>
经过再仔细看别人对任务队列的介绍,才知道,同步执行的js代码其实就算一个macrotask(准确说是每一个script标签内的代码都是一个macrotask),所以上面的规则中说的 先取出一个macrotask执行 是没有问题的。
网上很多文章都是像上面这样解释的,我也一直认为这是HTML对事件循环的规范,我们记着就是。直到最近看了李银城大佬的文章(见文末的参考链接),我才恍然大悟,之前看的文章都没有明确地从浏览器的多线程模型这个角度分析,所以让我们觉得浏览器的事件循环是基于上述的约定,但其实这是浏览器的多线程模型导致的结果。
浏览器的各种线程都是常驻线程,它们运行在一个for死循环里面,每个线程都有属于自己的若干任务队列,线程自己或者其它线程都可能通过PostTask向这些任务队列添加任务,这些线程会不断地从自己的任务队列中取出任务执行,或者是处于睡眠状态直到设定的时间或者是有人PostTask的时候把它们唤醒。