延迟0秒有啥用?这里设计的到一个JS的代码执行流程的问题

一句话总结就是: JS是单线程引擎,它把任务放到队列中,不会同步去执行,必须在完成一个任务后才开始另外一个任务

这里涉及到几个概念:宏任务微任务 还有 同步任务

先看一个JS的执行流程

JavaScript执行任务的主流程
宏任务和微任务的关系
从宏任务和微任务的循环的流程来看:宏任务的优先级 大于 微任务。

为啥要区分宏任务和微任务?而且怎么区分宏任务和微任务?

这里涉及到另一个问题:你JS虽然是单线程的,但 浏览器 是多线程的。

一个浏览器至少实现三个常驻线程:javascript引擎线程GUI渲染线程浏览器事件触发线程

1. JS引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。

2. GUI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)

《 单线程的JavaScript 》

粗俗一点讲: JS引擎线程和GUI渲染线程 互斥,事件触发线程穿梭其中

“你扯这么多,跟宏任务和微任务有半毛钱关系?”

这里补充一个概念:页面的渲染是穿插在每个宏任务执行之间的。

这样,JS引擎线程里面包含:宏任务和微任务的话,执行流程就如下了

宏任务–>界面渲染–>微任务–>事件循环–> 宏任务–>界面渲染–>微任务 ….

因为JS线程是跟界面渲染是互斥的,但有JS事件又不需要更新界面。所以执行完成之后不需要去更新界面的操作,就把它们归类到微任务,把需要更新界面操作的就归类的宏任务,这样是不是就理解了。

宏任务

#浏览器Node
I/O
setTimeout
setInterval
setImmediate
requestAnimationFrame

微任务

#浏览器Node
process.nextTick
MutationObserver
Promise.then catch finally

从上面的两个表。终于看到了 setTimeout 这函数,它属于宏任务。所以我们终于知道:setTimeout设置为0的到底有什么作用了吧?那就是改变他所调用的函数的优先级

Leave a Reply

Your email address will not be published. Required fields are marked *