默认情况下,script脚本会阻塞文档的解析渲染
浏览器解析文档时,默认是按照排列顺序向下解析的,当遇到script标签时,和其他标签元素一样(例如一个div),会先解析该元素(脚本),解析完成后再继续向下走完成剩余文档的解析和渲染。
也就是说默认情况下,script脚本会阻塞文档的解析渲染。
注意,如果我们的script脚本是放在页面底部的内联脚本,那么它对文档的解析渲染,在结果上影响不大。
但如果script脚本是外部脚本(通过网址引入的那种),那么这个脚本需要下载和解析执行,这期间会阻塞浏览器对文档的向下解析渲染,直至脚本下载执行完成,才会继续向下解析渲染。如果这个脚本出错了,可能还会导致整个页面永远无法正常渲染呈现。
注意,DOM树的生成是受JavaScript代码执行影响的,JavaScript代码会“阻塞”页面UI的渲染。
属性defer和asyn,script脚本不会阻塞文档的解析渲染
script标签有两个属性,一个是defer(延迟),二是asyn(异步),这两个属性都可以改变脚本的加载执行方式
-
defer(延迟):延迟是指当浏览器解析到script脚本时,会继续向下加载(但不执行,是异步)文档,等到文档载入解析完成且可以操作文档时,才开始执行脚本。
当有多个的时候:这些脚本会按照他们在文档中排列的顺序载入执行。 -
asyn(异步):异步是指当浏览器解析到script脚本时,会立刻加载和执行脚本,但同时浏览器解析器也会继续向下解析渲染文档,不会造成阻塞的现象。
当有多个的时候:会顺序开始触发载入,但谁先完成载入就谁先执行(执行顺序可能是无序不确定的)。
总结
-
一个script标签同时使用了async和defer,则执行async,忽略defer。
-
一个script标签只使用defer,且 defer=“defer”,则脚本将在页面完成解析时执行。
-
async和defer都不使用,遇到script脚本即会马上载入和执行脚本,此时会阻塞页面继续向下解析渲染。
-
只使用async且async=“async”,则脚本相对于页面的其余部分异步地执行。
所以,从浏览器解析器遇到script脚本的解析逻辑来看,script脚本可以阻塞浏览器继续渲染,也可以不阻塞,分两种情形:默认情况下,script 脚本会阻塞浏览器继续渲染,但可以通过 script 的 async 与 defer 属性改变这种状况。