<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] # 渲染引擎工作流程 如下圖所示為渲染引擎的渲染流程示意圖,其以HTML/JavaScript/CSS等文件作為輸入,以可視化內容作為輸出。 ![](https://box.kancloud.cn/99fed7d2c4cfe228565907a8bf00fbd3_3078x615.png) 1. **Parsing HTML to Construct DOM Tree** 渲染引擎使用HTML解析器(調用XML解析器)解析HTML(XML)文檔,將各個HTML(XML)元素逐個轉化成DOM節點,從而生成DOM樹。 同時,渲染引擎使用CSS解析器解析外部CSS文件以及HTML(XML)元素中的樣式規則。元素中帶有視覺指令的樣式規則將用于下一步,以創建另一個樹結構:渲染樹。 2. **Render Tree construction** 渲染引擎使用第1步CSS解析器解析得到的樣式規則,將其附著到DOM樹上,從而構成渲染樹。 渲染樹包含多個帶有視覺屬性(如顏色和尺寸)的矩形。這些矩形的排列順序就是它們將在屏幕上顯示的順序。 3. **Layout of Render Tree** 渲染樹構建完畢之后,進入本階段進行“布局”,也就是為每個節點分配一個應出現在屏幕上的確切坐標。 4. **Painting Render Tree** 渲染引擎將遍歷渲染樹,并調用顯示后端將每個節點繪制出來。 <br> <br> # 渲染引擎組成模塊 下圖所示為渲染引擎工作流程中各個步驟所對應的模塊,其中第1步和第2步涉及到多個模塊,并且耦合程度較高。這樣的設計會為了達到更好的用戶體驗,渲染引擎盡快將內容顯示在屏幕上。它不必等到整個HTML文檔解析完畢之后,就可以開始渲染樹構建和布局設置。在不斷接收和處理來自網絡的其余內容的同時,渲染引擎會將部分內容解析并顯示出來。 ![](https://box.kancloud.cn/4e1fdf6f2113e841bcf9804c6c20eeaf_3078x1497.png) 從圖中可以看出,渲染引擎主要包含(或調用)的模塊有: * **HTML(XML)解析器** 解析HTML(XML)文檔,主要作用是將HTML(XML)文檔轉換成DOM樹。 * **CSS解析器** 將DOM中的各個元素對象進行計算,獲取樣式信息,用于渲染樹的構建。 * **JavaScript解釋器** 使用JavaScript可以修改網頁的內容、CSS規則等。JavaScript解釋器能夠解釋JavaScript代碼,并通過DOM接口和CSSOM接口來修改網頁內容、樣式規則,從而改變渲染結果。 * **布局** DOM創建之后,渲染引擎將其中的元素對象與樣式規則進行結合,可以得到渲染樹。布局則是針對渲染樹,計算其各個元素的大小、位置等布局信息。 * **繪圖** 使用圖形庫將布局計算后的渲染樹繪制成可視化的圖像結果。 <br> <br> # 為什么操作 DOM 慢 因為 DOM 是屬于渲染引擎中的東西,而 JS 又是 JS 引擎中的東西。當我們通過 JS 操作 DOM 的時候,其實這個操作涉及到了兩個線程之間的通信,那么勢必會帶來一些性能上的損耗。操作 DOM 次數一多,也就等同于一直在進行線程之間的通信,并且操作 DOM 可能還會帶來重繪回流的情況,所以也就導致了性能上的問題。 <br> > 經典面試題:插入幾萬個 DOM,如何實現頁面不卡頓? 對于這道題目來說,首先我們肯定不能一次性把幾萬個 DOM 全部插入,這樣肯定會造成卡頓,所以解決問題的重點應該是如何分批次部分渲染 DOM。大部分人應該可以想到通過`requestAnimationFrame`的方式去循環的插入 DOM,其實還有種方式去解決這個問題:**虛擬滾動**(virtualized scroller)。 **這種技術的原理就是只渲染可視區域內的內容,非可見區域的那就完全不渲染了,當用戶在滾動的時候就實時去替換渲染的內容。** ![](https://box.kancloud.cn/68ad7133d494270aaa35629d94075fe4_1204x380.gif) <br> 即使列表很長,但是渲染的 DOM 元素永遠只有那么幾個,當我們滾動頁面的時候就會實時去更新 DOM,這個技術就能順利解決這道經典面試題。如果你想了解更多的內容可以了解下這個[react-virtualized](https://link.juejin.im/?target=https%3A%2F%2Fgithub.com%2Fbvaughn%2Freact-virtualized)。 <br> # 資源異步同步加載 首先渲染的前提是生成渲染樹,所以 HTML 和 CSS 肯定會阻塞渲染。如果你想渲染的越快,你越應該降低一開始需要渲染的文件**大小**,并且**扁平層級,優化選擇器**。 <br> 然后當瀏覽器在解析到`script`標簽時,會暫停構建 DOM,完成后才會從暫停的地方重新開始。也就是說,如果你想首屏渲染的越快,就越不應該在首屏就加載 JS 文件,這也是都建議將`script`標簽放在`body`標簽底部的原因。 <br> 當然在當下,并不是說`script`標簽必須放在底部,因為你可以給`script`標簽添加`defer`或者`async`屬性。 <br> ## 解析過程 ![](https://box.kancloud.cn/be80a7a35e1e8654494345fe3dc2b05b_452x397.png) ## 普通script 文檔解析的過程中,如果遇到`script`腳本,就會停止頁面的解析進行下載(但是Chrome會做一個優化,如果遇到`script`腳本,會快速的查看后邊有沒有需要下載其他資源的,如果有的話,會先下載那些資源,然后再進行下載`script`所對應的資源,這樣能夠節省一部分下載的時間)。 資源的下載是在解析過程中進行的,雖說`script1`腳本會很快的加載完畢,但是他前邊的`script2`并沒有加載&執行,所以他只能處于一個掛起的狀態,等待`script2`執行完畢后再執行。 當這兩個腳本都執行完畢后,才會繼續解析頁面。 ![](https://box.kancloud.cn/2dd49b9b7f85a20e441652fb78388a09_1640x326.png) <br> ## defer * 如果`script`標簽設置了`defer`性,則瀏覽器會異步的下載該文件并且不會影響到后續`DOM`的渲染; * 如果有多個設置了`defer`的`script`標簽存在,則會按照順序執行所有的`script`; * `defer`腳本會在文檔渲染完畢后,`DOMContentLoaded`事件調用前執行。 * 文檔解析時,遇到設置了`defer`的腳本,就會在后臺進行下載,但是并不會阻止文檔的渲染,當頁面解析&渲染完畢后。 * 會等到所有的`defer`腳本加載完畢并按照順序執行,執行完畢后會觸發`DOMContentLoaded`事件。 ![](https://box.kancloud.cn/96e451a0d1bd7228eaa4160303f77d6d_1320x282.png) <br> 使用場景 如果你的腳本代碼依賴于頁面中的`DOM`元素(文檔是否解析完畢),或者被其他腳本文件依賴。 **例:** 1. 評論框 2. 代碼語法高亮 3. `polyfill.js` <br> ## async * `async`的設置,會使得`script`腳本異步的加載并在允許的情況下執行 * `async`的執行,并不會按著`script`在頁面中的順序來執行,而是誰先加載完誰執行。 * `async`腳本會在加載完畢后執行。 * `async`腳本的加載不計入`DOMContentLoaded`事件統計,也就是說下圖兩種情況都是有可能發生的 ![](https://box.kancloud.cn/85943b897cd9bca91f42f23daeee8637_1310x264.png) ![](https://box.kancloud.cn/c1033591cd8f38cb1d467a4752537b93_880x168.png) <br> 使用場景 如果你的腳本并不關心頁面中的`DOM`元素(文檔是否解析完畢),并且也不會產生其他腳本需要的數據。 **例:** 1. 百度統計 > 如果不太能確定的話,用`defer`總是會比`async`穩定。 <br> # 參考資料 [現代瀏覽器工作原理(一)](http://chuquan.me/2018/01/21/browser-architecture-overview/) 前端面試之道 - 掘金手冊 [淺談script標簽中的async和defer](https://www.cnblogs.com/jiasm/p/7683930.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看