为何setTimeout的回调会在文档解析完成后才执行?
为什么setTimeout回调会在文档解析完成后执行
你提到的代码示例如下:
<!DOCTYPE html> <html> <head> <script> setTimeout(() => console.log(document.readyState)); </script> </head> <body> <!-- 大量待解析的HTML内容,解析耗时较长 --> </body> </html>
要解释这个现象,核心要搞懂浏览器主线程的任务调度规则:
- 浏览器的页面渲染、JS执行、HTML解析全部运行在主线程上,这是一个单线程,同一时间只能做一件事。
- HTML解析属于主线程的同步优先级任务,只要解析没完成,主线程就会一直被占用,不会去执行其他异步任务。
setTimeout的回调属于宏任务,调用setTimeout的时候只是把回调函数注册到了宏任务队列,并不会立刻执行。哪怕延迟设为0,也必须等到当前主线程的所有同步任务全部执行完毕、主线程处于空闲状态时,才会从宏任务队列里取出回调执行。- 你预期的竞态不会出现,本质是因为HTML解析和setTimeout回调根本不是同一优先级的任务:同步的解析任务一定会先全部跑完,才会轮到异步的宏任务执行,所以回调执行时document.readyState必然已经是complete。
注意:这个写法属于非规范的黑盒hack,不推荐在生产环境使用。如果浏览器当前有其他高优先级同步任务阻塞了主线程,或者后续有其他更早注册的宏任务插队,也可能出现回调执行时文档还没解析完成的情况。正规的实现方式应该是监听
DOMContentLoaded事件(DOM解析完成触发)或者load事件(所有资源加载完成触发)。
内容的提问来源于stack exchange,提问作者emccorson
相关产品推荐
相关产品推荐

