通過瀏覽器渲染過程來進行前端優化


 
介紹
 
  做web開發,我個人覺得必須要弄清楚瀏覽器的渲染過程,否則我們很難進行前端優化。
  我今天就簡單說一下頁面加載和前端優化。
 
頁面加載
 
我按照最簡單的方式進行描述,實際上更復雜,不管是在瀏覽器端還是服務端,比如dns解析,代理服務器,負載均衡器等等。

 
1、用戶訪問網頁,發送一個http請求到網絡服務器。
2、網絡服務器(應用服務器)解析請求,發送請求給數據庫服務器。
3、數據服務器返回數據給網絡服務器,網絡服務器解析數據,並生成html文件內容放入http response中,返回給瀏覽器。
4、瀏覽器解析http response。
5、瀏覽器創建DOM樹。
6、瀏覽器下載css,並應用在DOM樹上,進行渲染。
7、瀏覽器下載js,並解析執行js。
 

 
 
缺陷
 
以上整個流程中,如果其中任何一個流程出現問題,都不能順利的渲染頁面。
 
服務端:
  網絡服務器:無法獲取到資源文件(404),或者由於並發的原因暫時無法處理你的請求(最常見的500錯誤),你的瀏覽器會長時間處於空白狀態,直到服務器返回狀態,或者進行超時處理。
  數據層:如果服務器停止,或忙於處理大數據等等,長時間無法返回數據給網絡服務器,那么網絡服務器一直處於等待狀態中,如果請求量達到最大值,那么后面的請求都被堵塞,從而無法及時返回內容給瀏覽器。
 
客戶端:
  JavaScript:如果你的js寫在body中的div里,而且這個js執行非常復雜的邏輯,那么整個頁面處於等待狀態中。
  不論js代碼是內聯還是包含在一個不相干的外部文件中,頁面下載和解析過程肯定會停下,等待腳本執行完成這些處理,然后才能繼續進行。——大多數瀏覽器使用單進程處理JavaScript的多個任務,同一時間只能有一個任務執行。
  CSS:可以同時下載多個CSS文件。
      如果我們把CSS樣式放在頁面底部,雖然使頁面內容能更快的加載 (因為將加載css 文件的時間放在最后,從而使頁面內容先顯示出來),但這樣的內容是沒有樣式的,在CSS文件加載進來后,瀏覽器再對DOM使用樣式,會出現我們常說的“無樣式之閃爍”。
      更討厭的是,上下都放置CSS樣式,瀏覽器會首先按照上面的進行渲染,等到下面的樣式上來,再按照下面的樣式進行回流和重繪,用戶感覺很差。
 
注意兩個詞“repaint"和"reflow"。
  repaint(重繪)是在一個元素的外觀被改變,但沒有改變布局的情況下發生。——如果只是改變某個元素的背景色、文字顏色、邊框顏色等等不影響它周圍或內部布局的屬性,將只會引起瀏覽器repaint。
  reflow(回流):瀏覽器發現某個部分發生了點變化影響了布局,需要倒回去重新渲染,這個回退的過程就叫回流。
總結:以上兩種嚴重影響用戶體驗,會無意識的流失用戶。
 

 
解決方案
 
 服務端:方式比較多,可以從架構上說(這個內容太多了,什么負載均衡了,什么緩存了,什么主從了),但是今天主要討論語言層面。
    我們可以使用逐步返回內容的方式,輸送數據給瀏覽器,如我們可以使用php的flush,把整個head部分,半個body加一部分div返回給瀏覽器,進行渲染,然后把其他部分逐步輸送到瀏覽器。
    我們可以在服務端使用多線程或多進程的方式並發去進行數據處理。如php常見的
do {
  $mrc = curl_multi_exec($mh, $active);
}while($mrc==CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK){
  if (curl_multi_select($mh) != -1){
    do {
      $mrc = curl_multi_exec($mh,$active);
    }while($mrc==CURLM_CALL_MULTI_PERFORM);
  }
}

或者

<?php
while (count($sockets)) {
    $read = $write = $sockets;
    $n = stream_select($read,$write, $e, $timeout);
    if ($n > 0) {
        foreach ($read as $r) {
            $id = array_search($r, $sockets);
            $data = fread($r, 8192);
            if (strlen($data) == 0) {
                fclose($r);
                unset ($sockets[$id]);
            }else {
                $retdata[$id] .= $data;
            }   
        }   
        $retdata[$id] = preg_replace('/^HTTP(.*?)\r\n\r\n/is',<em>, $retdata[$id]);</em>
            foreach ($write as $w) {
                if (!is_resource($w))continue;
                $id = array_search($w, $sockets);
                fwrite($w, "GET /" . $url[$id] . "HTTP/1.0\r\nHost: " . $hosts[$id] ."\r\n\r\n");
                $status[$id] = 1;
            }   
    }else {
        break;
    }   
}

 

JavaScript:

  1、把腳本進行壓縮(移除不必要的字符,注釋以及空行)。

  2、對部分js文件進行合並,以減少http的請求個數,以減少服務器端的壓力——但是要量力而行,因為如果你的js文件很大,下載很慢的話,很多功能都不能正常進行,我們可以按照業務進行合並。

  3、使用外部js文件。因為現在很多瀏覽器都有緩存,明顯會減少http請求數。

  4、將腳本放在頁面底部。先讓用戶看到內容,然后再加載js,這樣用戶會感覺頁面加載速度很快。

CSS:

  1、合並多個css文件,以減少http的請求個數,以減少服務器端的壓力。

  2、使用外部css文件。主要原因是瀏覽器緩存,以減少http請求。

  3、放在頁面頂部(head標簽處),防止出現“無樣式內容的閃爍”。

 

 

總結
 

以上是我通過瀏覽器的加載過程,來進行的前端優化,大家有什么更好的方式,不妨告知一、二。

 

 

推薦
 
 

 分享到騰訊微博

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM