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 放在頭部

相關文章
相關標籤/搜索