js和css对dom的阻塞

参考: https://juejin.im/post/6844903497599549453#heading-6css

前端页面开发时,习惯于css文件置于头部head中,js文件置于body的底部。这样作的缘由是css不会阻塞dom的解析,js会阻塞dom的解析。html

css不影响dom的解析,那是否影响dom渲染?js经过增长defer或async属性,会对文件的加载执行有什么影响?(以chrome,node,为测试环境)前端

浏览器对dom的处理分为两步,首先是dom的解析(分段解析,解析出一部分,就渲染一部分),而后再是dom树的渲染,渲染的过程是须要css树的参与的(若是有的话);浏览器对html文件的解析自上而下进行,解析过程结束,即开始准备进行渲染。node

样式的变化会引发页面的重排和重绘,若是在明知有css文件正在下载的状况下,进行渲染,css加载完成后,会再次的进行渲染,至关于前次的渲染工做是无用功,因此浏览器为了不无用工做,会有优化动做:chrome

  • 等待下载中的css文件完成,再去渲染。
  • js执行前,会渲染一次已经解析的dom,保证js获取的dom是最新的。

有了上面的基础后,咱们就能够作出分析了。浏览器

1.css位置框架

      a.css文件在dom前(body上)dom

          结论:等待css加载完成,进行渲染异步

     b.css文件在dom中(body中)async

        结论:link前的dom首次无样式渲染,css加载完成,全部dom进行有样式的渲染

    c.css文件在dom后(body下)

        结论:首次无样式渲染,css加载完成,全部dom进行有样式的渲染

    总之,在渲染前被解析到的css文件将阻塞dom的渲染。

2.js位置

    a.js文件在dom前(body上)

        结论:等待js加载并执行完成,进行渲染。(console.log(dom)为null)

    b.js文件在dom中(body中)

        结论:script前的dom首次渲染,js加载并执行完成,后面的dom进行渲染。(console.log(dom)只有script前的dom)

    c.js文件在dom下(body下)

        结论:不影响dom的渲染。(console.log(dom)获取全部dom)

    总之,这个很少说(不考虑defer,async),任何位置的js文件对它以后的dom的解析和渲染都会阻塞。

3.js + defer(推迟)

    这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。

(DOMContentLoaded事件在初始HTML文档彻底加载和解析以后触发,而无需等待样式表、图像和子框架完成加载)

    因此加了这个属性的scritp,将不会阻塞dom的解析(没说不阻塞渲染);但仍会等待它以前的css文件的下载

4. js+ async(异步)

    对于普通脚本,该属性可以消除解析阻塞的 Javascript;那么普通脚本会被并行请求,并尽快解析和执行。 

  •  只有js时,defer和async的效果差很少,执行时间没有差异,能够获取dom,但img可能还未加载完成。
  •  当存在css时,defer模式须要等待css的加载,再触发DOMContentLoaded事件 css会阻塞渲染。
  •  当存在css时,async模式没有影响
  •  defer阻塞DOMContentLoaded;async阻塞Load事件

  5. css + js

        a. css在前,js在后(不管在什么位置)

            结论:css存在阻塞。js执行前,须要渲染一次,渲染dom须要等待以解析的link加载完成。

    b. js在前,css在后(不管在什么位置)

            结论:js优先解析和执行,css彻底不影响。

    总结:1.css文件应该尽早加载,避免阻塞js的执行,因此应放在head中

                2.js会阻塞后面的dom的解析和渲染,因此应放在尾部,或者添加defer/async 放在头部

相关文章
相关标签/搜索