99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

前端面試 性能優(yōu)化篇

2023-02-17 10:51 更新

一、CDN


1. CDN的概念

CDN(Content Delivery Network,內(nèi)容分發(fā)網(wǎng)絡)是指一種通過互聯(lián)網(wǎng)互相連接的電腦網(wǎng)絡系統(tǒng),利用最靠近每位用戶的服務器,更快、更可靠地將音樂、圖片、視頻、應用程序及其他文件發(fā)送給用戶,來提供高性能、可擴展性及低成本的網(wǎng)絡內(nèi)容傳遞給用戶。

典型的CDN系統(tǒng)由下面三個部分組成:

  • 分發(fā)服務系統(tǒng):最基本的工作單元就是Cache設備,cache(邊緣cache)負責直接響應最終用戶的訪問請求,把緩存在本地的內(nèi)容快速地提供給用戶。同時cache還負責與源站點進行內(nèi)容同步,把更新的內(nèi)容以及本地沒有的內(nèi)容從源站點獲取并保存在本地。Cache設備的數(shù)量、規(guī)模、總服務能力是衡量一個CDN系統(tǒng)服務能力的最基本的指標。
  • 負載均衡系統(tǒng):主要功能是負責對所有發(fā)起服務請求的用戶進行訪問調(diào)度,確定提供給用戶的最終實際訪問地址。兩級調(diào)度體系分為全局負載均衡(GSLB)和本地負載均衡(SLB)。全局負載均衡主要根據(jù)用戶就近性原則,通過對每個服務節(jié)點進行“最優(yōu)”判斷,確定向用戶提供服務的cache的物理位置。本地負載均衡主要負責節(jié)點內(nèi)部的設備負載均衡
  • 運營管理系統(tǒng):運營管理系統(tǒng)分為運營管理和網(wǎng)絡管理子系統(tǒng),負責處理業(yè)務層面的與外界系統(tǒng)交互所必須的收集、整理、交付工作,包含客戶管理、產(chǎn)品管理、計費管理、統(tǒng)計分析等功能。

2. CDN的作用

CDN一般會用來托管Web資源(包括文本、圖片和腳本等),可供下載的資源(媒體文件、軟件、文檔等),應用程序(門戶網(wǎng)站等)。使用CDN來加速這些資源的訪問。

(1)在性能方面,引入CDN的作用在于:

  • 用戶收到的內(nèi)容來自最近的數(shù)據(jù)中心,延遲更低,內(nèi)容加載更快
  • 部分資源請求分配給了CDN,減少了服務器的負載

(2)在安全方面,CDN有助于防御DDoS、MITM等網(wǎng)絡攻擊:

  • 針對DDoS:通過監(jiān)控分析異常流量,限制其請求頻率
  • 針對MITM:從源服務器到 CDN 節(jié)點到 ISP(Internet Service Provider),全鏈路 HTTPS 通信

除此之外,CDN作為一種基礎的云服務,同樣具有資源托管、按需擴展(能夠應對流量高峰)等方面的優(yōu)勢。

3. CDN的原理

CDN和DNS有著密不可分的聯(lián)系,先來看一下DNS的解析域名過程,在瀏覽器輸入 www.test.com 的解析過程如下:

(1) 檢查瀏覽器緩存

(2)檢查操作系統(tǒng)緩存,常見的如hosts文件

(3)檢查路由器緩存

(4)如果前幾步都沒沒找到,會向ISP(網(wǎng)絡服務提供商)的LDNS服務器查詢

(5)如果LDNS服務器沒找到,會向根域名服務器(Root Server)請求解析,分為以下幾步:

  • 根服務器返回頂級域名(TLD)服務器如 ?.com?,?.cn?,?.org?等的地址,該例子中會返回 ?.com?的地址
  • 接著向頂級域名服務器發(fā)送請求,然后會返回次級域名(SLD)服務器的地址,本例子會返回 ?.test?的地址
  • 接著向次級域名服務器發(fā)送請求,然后會返回通過域名查詢到的目標IP,本例子會返回 ?www.test.com?的地址
  • Local DNS Server會緩存結(jié)果,并返回給用戶,緩存在系統(tǒng)中

CDN的工作原理:

(1)用戶未使用CDN緩存資源的過程:

  1. 瀏覽器通過DNS對域名進行解析(就是上面的DNS解析過程),依次得到此域名對應的IP地址
  2. 瀏覽器根據(jù)得到的IP地址,向域名的服務主機發(fā)送數(shù)據(jù)請求
  3. 服務器向瀏覽器返回響應數(shù)據(jù)

(2)用戶使用CDN緩存資源的過程:

  1. 對于點擊的數(shù)據(jù)的URL,經(jīng)過本地DNS系統(tǒng)的解析,發(fā)現(xiàn)該URL對應的是一個CDN專用的DNS服務器,DNS系統(tǒng)就會將域名解析權(quán)交給CNAME指向的CDN專用的DNS服務器。
  2. CND專用DNS服務器將CND的全局負載均衡設備IP地址返回給用戶
  3. 用戶向CDN的全局負載均衡設備發(fā)起數(shù)據(jù)請求
  4. CDN的全局負載均衡設備根據(jù)用戶的IP地址,以及用戶請求的內(nèi)容URL,選擇一臺用戶所屬區(qū)域的區(qū)域負載均衡設備,告訴用戶向這臺設備發(fā)起請求
  5. 區(qū)域負載均衡設備選擇一臺合適的緩存服務器來提供服務,將該緩存服務器的IP地址返回給全局負載均衡設備
  6. 全局負載均衡設備把服務器的IP地址返回給用戶
  7. 用戶向該緩存服務器發(fā)起請求,緩存服務器響應用戶的請求,將用戶所需內(nèi)容發(fā)送至用戶終端。

如果緩存服務器沒有用戶想要的內(nèi)容,那么緩存服務器就會向它的上一級緩存服務器請求內(nèi)容,以此類推,直到獲取到需要的資源。最后如果還是沒有,就會回到自己的服務器去獲取資源。

image

CNAME(意為:別名):在域名解析中,實際上解析出來的指定域名對應的IP地址,或者該域名的一個CNAME,然后再根據(jù)這個CNAME來查找對應的IP地址。

4. CDN的使用場景

  • 使用第三方的CDN服務:如果想要開源一些項目,可以使用第三方的CDN服務
  • 使用CDN進行靜態(tài)資源的緩存:將自己網(wǎng)站的靜態(tài)資源放在CDN上,比如js、css、圖片等??梢詫⒄麄€項目放在CDN上,完成一鍵部署。
  • 直播傳送:直播本質(zhì)上是使用流媒體進行傳送,CDN也是支持流媒體傳送的,所以直播完全可以使用CDN來提高訪問速度。CDN在處理流媒體的時候與處理普通靜態(tài)文件有所不同,普通文件如果在邊緣節(jié)點沒有找到的話,就會去上一層接著尋找,但是流媒體本身數(shù)據(jù)量就非常大,如果使用回源的方式,必然會帶來性能問題,所以流媒體一般采用的都是主動推送的方式來進行。

二、懶加載


1. 懶加載的概念

懶加載也叫做延遲加載、按需加載,指的是在長網(wǎng)頁中延遲加載圖片數(shù)據(jù),是一種較好的網(wǎng)頁性能優(yōu)化的方式。在比較長的網(wǎng)頁或應用中,如果圖片很多,所有的圖片都被加載出來,而用戶只能看到可視窗口的那一部分圖片數(shù)據(jù),這樣就浪費了性能。

如果使用圖片的懶加載就可以解決以上問題。在滾動屏幕之前,可視化區(qū)域之外的圖片不會進行加載,在滾動屏幕時才加載。這樣使得網(wǎng)頁的加載速度更快,減少了服務器的負載。懶加載適用于圖片較多,頁面列表較長(長列表)的場景中。

2. 懶加載的特點

  • 減少無用資源的加載:使用懶加載明顯減少了服務器的壓力和流量,同時也減小了瀏覽器的負擔。
  • 提升用戶體驗: 如果同時加載較多圖片,可能需要等待的時間較長,這樣影響了用戶體驗,而使用懶加載就能大大的提高用戶體驗。
  • 防止加載過多圖片而影響其他資源文件的加載 :會影響網(wǎng)站應用的正常使用。

3. 懶加載的實現(xiàn)原理

圖片的加載是由 src引起的,當對 src賦值時,瀏覽器就會請求圖片資源。根據(jù)這個原理,我們使用HTML5 的 data-xxx屬性來儲存圖片的路徑,在需要加載圖片的時候,將 data-xxx中圖片的路徑賦值給 src,這樣就實現(xiàn)了圖片的按需加載,即懶加載。

注意:data-xxx 中的 xxx可以自定義,這里我們使用 data-src來定義。

懶加載的實現(xiàn)重點在于確定用戶需要加載哪張圖片,在瀏覽器中,可視區(qū)域內(nèi)的資源就是用戶需要的資源。所以當圖片出現(xiàn)在可視區(qū)域時,獲取圖片的真實地址并賦值給圖片即可。

使用原生JavaScript實現(xiàn)懶加載:

知識點:

(1)window.innerHeight 是瀏覽器可視區(qū)的高度 document.documentElement.clientHeight

(2)document.body.scrollTop || document.documentElement.scrollTop 是瀏覽器滾動的過的距離

(3)imgs.offsetTop 是元素頂部距離文檔頂部的高度(包括滾動條的距離)

(4)圖片加載條件:img.offsetTop < window.innerHeight + document.body.scrollTop;

圖示:

image

代碼實現(xiàn):

<div class="container">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
     <img src="loading.gif"  data-src="pic.png">
</div>
<script>
var imgs = document.querySelectorAll('img');
function lozyLoad(){
        var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        var winHeight= window.innerHeight;
        for(var i=0;i < imgs.length;i++){
            if(imgs[i].offsetTop < scrollTop + winHeight ){
                imgs[i].src = imgs[i].getAttribute('data-src');
            }
        }
    }
  window.onscroll = lozyLoad();
</script>

4. 懶加載與預加載的區(qū)別

這兩種方式都是提高網(wǎng)頁性能的方式,兩者主要區(qū)別是一個是提前加載,一個是遲緩甚至不加載。懶加載對服務器前端有一定的緩解壓力作用,預加載則會增加服務器前端壓力。

  • 懶加載也叫延遲加載,指的是在長網(wǎng)頁中延遲加載圖片的時機,當用戶需要訪問時,再去加載,這樣可以提高網(wǎng)站的首屏加載速度,提升用戶的體驗,并且可以減少服務器的壓力。它適用于圖片很多,頁面很長的電商網(wǎng)站的場景。懶加載的實現(xiàn)原理是,將頁面上的圖片的 src 屬性設置為空字符串,將圖片的真實路徑保存在一個自定義屬性中,當頁面滾動的時候,進行判斷,如果圖片進入頁面可視區(qū)域內(nèi),則從自定義屬性中取出真實路徑賦值給圖片的 src 屬性,以此來實現(xiàn)圖片的延遲加載。
  • 預加載指的是將所需的資源提前請求加載到本地,這樣后面在需要用到時就直接從緩存取資源。通過預加載能夠減少用戶的等待時間,提高用戶的體驗。我了解的預加載的最常用的方式是使用 js 中的 image 對象,通過為 image 對象來設置 scr 屬性,來實現(xiàn)圖片的預加載。

三、回流與重繪


1. 回流與重繪的概念及觸發(fā)條件

(1)回流

當渲染樹中部分或者全部元素的尺寸、結(jié)構(gòu)或者屬性發(fā)生變化時,瀏覽器會重新渲染部分或者全部文檔的過程就稱為回流。

下面這些操作會導致回流:

  • 頁面的首次渲染
  • 瀏覽器的窗口大小發(fā)生變化
  • 元素的內(nèi)容發(fā)生變化
  • 元素的尺寸或者位置發(fā)生變化
  • 元素的字體大小發(fā)生變化
  • 激活CSS偽類
  • 查詢某些屬性或者調(diào)用某些方法
  • 添加或者刪除可見的DOM元素

在觸發(fā)回流(重排)的時候,由于瀏覽器渲染頁面是基于流式布局的,所以當觸發(fā)回流時,會導致周圍的DOM元素重新排列,它的影響范圍有兩種:

  • 全局范圍:從根節(jié)點開始,對整個渲染樹進行重新布局
  • 局部范圍:對渲染樹的某部分或者一個渲染對象進行重新布局

(2)重繪

當頁面中某些元素的樣式發(fā)生變化,但是不會影響其在文檔流中的位置時,瀏覽器就會對元素進行重新繪制,這個過程就是重繪。

下面這些操作會導致回流:

  • color、background 相關屬性:background-color、background-image 等
  • outline 相關屬性:outline-color、outline-width 、text-decoration
  • border-radius、visibility、box-shadow

注意: 當觸發(fā)回流時,一定會觸發(fā)重繪,但是重繪不一定會引發(fā)回流。

2. 如何避免回流與重繪?

減少回流與重繪的措施:

  • 操作DOM時,盡量在低層級的DOM節(jié)點進行操作
  • 不要使用 ?table?布局, 一個小的改動可能會使整個 ?table?進行重新布局
  • 使用CSS的表達式
  • 不要頻繁操作元素的樣式,對于靜態(tài)頁面,可以修改類名,而不是樣式。
  • 使用absolute或者fixed,使元素脫離文檔流,這樣他們發(fā)生變化就不會影響其他元素
  • 避免頻繁操作DOM,可以創(chuàng)建一個文檔片段 ?documentFragment?,在它上面應用所有DOM操作,最后再把它添加到文檔中
  • 將元素先設置 ?display: none?,操作結(jié)束后再把它顯示出來。因為在display屬性為none的元素上進行的DOM操作不會引發(fā)回流和重繪。
  • 將DOM的多個讀操作(或者寫操作)放在一起,而不是讀寫操作穿插著寫。這得益于瀏覽器的渲染隊列機制

瀏覽器針對頁面的回流與重繪,進行了自身的優(yōu)化——渲染隊列

瀏覽器會將所有的回流、重繪的操作放在一個隊列中,當隊列中的操作到了一定的數(shù)量或者到了一定的時間間隔,瀏覽器就會對隊列進行批處理。這樣就會讓多次的回流、重繪變成一次回流重繪。

上面,將多個讀操作(或者寫操作)放在一起,就會等所有的讀操作進入隊列之后執(zhí)行,這樣,原本應該是觸發(fā)多次回流,變成了只觸發(fā)一次回流。

3. 如何優(yōu)化動畫?

對于如何優(yōu)化動畫,我們知道,一般情況下,動畫需要頻繁的操作DOM,就就會導致頁面的性能問題,我們可以將動畫的 position屬性設置為 absolute或者 fixed,將動畫脫離文檔流,這樣他的回流就不會影響到頁面了。

4. documentFragment 是什么?用它跟直接操作 DOM 的區(qū)別是什么?

MDN中對 documentFragment的解釋:

DocumentFragment,文檔片段接口,一個沒有父對象的最小文檔對象。它被作為一個輕量版的 Document使用,就像標準的document一樣,存儲由節(jié)點(nodes)組成的文檔結(jié)構(gòu)。與document相比,最大的區(qū)別是DocumentFragment不是真實 DOM 樹的一部分,它的變化不會觸發(fā) DOM 樹的重新渲染,且不會導致性能等問題。

當我們把一個 DocumentFragment 節(jié)點插入文檔樹時,插入的不是 DocumentFragment 自身,而是它的所有子孫節(jié)點。在頻繁的DOM操作時,我們就可以將DOM元素插入DocumentFragment,之后一次性的將所有的子孫節(jié)點插入文檔中。和直接操作DOM相比,將DocumentFragment 節(jié)點插入DOM樹時,不會觸發(fā)頁面的重繪,這樣就大大提高了頁面的性能。

四、節(jié)流與防抖


1. 對節(jié)流與防抖的理解

  • 函數(shù)防抖是指在事件被觸發(fā) n 秒后再執(zhí)行回調(diào),如果在這 n 秒內(nèi)事件又被觸發(fā),則重新計時。這可以使用在一些點擊請求的事件上,避免因為用戶的多次點擊向后端發(fā)送多次請求。
  • 函數(shù)節(jié)流是指規(guī)定一個單位時間,在這個單位時間內(nèi),只能有一次觸發(fā)事件的回調(diào)函數(shù)執(zhí)行,如果在同一個單位時間內(nèi)某事件被觸發(fā)多次,只有一次能生效。節(jié)流可以使用在 scroll 函數(shù)的事件監(jiān)聽上,通過事件節(jié)流來降低事件調(diào)用的頻率。

防抖函數(shù)的應用場景:

  • 按鈕提交場景:防?多次提交按鈕,只執(zhí)?最后提交的?次
  • 服務端驗證場景:表單驗證需要服務端配合,只執(zhí)??段連續(xù)的輸?事件的最后?次,還有搜索聯(lián)想詞功能類似?存環(huán)境請?lodash.debounce

節(jié)流函數(shù)的適?場景:

  • 拖拽場景:固定時間內(nèi)只執(zhí)??次,防?超?頻次觸發(fā)位置變動
  • 縮放場景:監(jiān)控瀏覽器resize
  • 動畫場景:避免短時間內(nèi)多次觸發(fā)動畫引起性能問題

2. 實現(xiàn)節(jié)流函數(shù)和防抖函數(shù)

函數(shù)防抖的實現(xiàn):

function debounce(fn, wait) {
  var timer = null;

  return function() {
    var context = this,
      args = [...arguments];

    // 如果此時存在定時器的話,則取消之前的定時器重新記時
    if (timer) {
      clearTimeout(timer);
      timer = null;
    }

    // 設置定時器,使事件間隔指定事件后執(zhí)行
    timer = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  };
}

函數(shù)節(jié)流的實現(xiàn):

// 時間戳版
function throttle(fn, delay) {
  var preTime = Date.now();

  return function() {
    var context = this,
      args = [...arguments],
      nowTime = Date.now();

    // 如果兩次時間間隔超過了指定時間,則執(zhí)行函數(shù)。
    if (nowTime - preTime >= delay) {
      preTime = Date.now();
      return fn.apply(context, args);
    }
  };
}

// 定時器版
function throttle (fun, wait){
  let timeout = null
  return function(){
    let context = this
    let args = [...arguments]
    if(!timeout){
      timeout = setTimeout(() => {
        fun.apply(context, args)
        timeout = null 
      }, wait)
    }
  }
}

五、圖片優(yōu)化


1. 如何對項目中的圖片進行優(yōu)化?

  1. 不用圖片。很多時候會使用到很多修飾類圖片,其實這類修飾圖片完全可以用 CSS 去代替。
  2. 對于移動端來說,屏幕寬度就那么點,完全沒有必要去加載原圖浪費帶寬。一般圖片都用 CDN 加載,可以計算出適配屏幕的寬度,然后去請求相應裁剪好的圖片。
  3. 小圖使用 base64 格式
  4. 將多個圖標文件整合到一張圖片中(雪碧圖)
  5. 選擇正確的圖片格式:
    • 對于能夠顯示 WebP 格式的瀏覽器盡量使用 WebP 格式。因為 WebP 格式具有更好的圖像數(shù)據(jù)壓縮算法,能帶來更小的圖片體積,而且擁有肉眼識別無差異的圖像質(zhì)量,缺點就是兼容性并不好
    • 小圖使用 PNG,其實對于大部分圖標這類圖片,完全可以使用 SVG 代替
    • 照片使用 JPEG

2. 常見的圖片格式及使用場景

(1)BMP是無損的、既支持索引色也支持直接色的點陣圖。這種圖片格式幾乎沒有對數(shù)據(jù)進行壓縮,所以BMP格式的圖片通常是較大的文件。

(2)GIF是無損的、采用索引色的點陣圖。采用LZW壓縮算法進行編碼。文件小,是GIF格式的優(yōu)點,同時,GIF格式還具有支持動畫以及透明的優(yōu)點。但是GIF格式僅支持8bit的索引色,所以GIF格式適用于對色彩要求不高同時需要文件體積較小的場景。

(3)JPEG是有損的、采用直接色的點陣圖。JPEG的圖片的優(yōu)點是采用了直接色,得益于更豐富的色彩,JPEG非常適合用來存儲照片,與GIF相比,JPEG不適合用來存儲企業(yè)Logo、線框類的圖。因為有損壓縮會導致圖片模糊,而直接色的選用,又會導致圖片文件較GIF更大。

(4)PNG-8是無損的、使用索引色的點陣圖。PNG是一種比較新的圖片格式,PNG-8是非常好的GIF格式替代者,在可能的情況下,應該盡可能的使用PNG-8而不是GIF,因為在相同的圖片效果下,PNG-8具有更小的文件體積。除此之外,PNG-8還支持透明度的調(diào)節(jié),而GIF并不支持。除非需要動畫的支持,否則沒有理由使用GIF而不是PNG-8。

(5)PNG-24是無損的、使用直接色的點陣圖。PNG-24的優(yōu)點在于它壓縮了圖片的數(shù)據(jù),使得同樣效果的圖片,PNG-24格式的文件大小要比BMP小得多。當然,PNG24的圖片還是要比JPEG、GIF、PNG-8大得多。

(6)SVG是無損的矢量圖。SVG是矢量圖意味著SVG圖片由直線和曲線以及繪制它們的方法組成。當放大SVG圖片時,看到的還是線和曲線,而不會出現(xiàn)像素點。這意味著SVG圖片在放大時,不會失真,所以它非常適合用來繪制Logo、Icon等。

(7)WebP是谷歌開發(fā)的一種新圖片格式,WebP是同時支持有損和無損壓縮的、使用直接色的點陣圖。從名字就可以看出來它是為Web而生的,什么叫為Web而生呢?就是說相同質(zhì)量的圖片,WebP具有更小的文件體積?,F(xiàn)在網(wǎng)站上充滿了大量的圖片,如果能夠降低每一個圖片的文件大小,那么將大大減少瀏覽器和服務器之間的數(shù)據(jù)傳輸量,進而降低訪問延遲,提升訪問體驗。目前只有Chrome瀏覽器和Opera瀏覽器支持WebP格式,兼容性不太好。

  • 在無損壓縮的情況下,相同質(zhì)量的WebP圖片,文件大小要比PNG小26%;
  • 在有損壓縮的情況下,具有相同圖片精度的WebP圖片,文件大小要比JPEG小25%~34%;
  • WebP圖片格式支持圖片透明度,一個無損壓縮的WebP圖片,如果要支持透明度只需要22%的格外文件大小。

六、Webpack優(yōu)化


1. 如何提?webpack的打包速度?

(1)優(yōu)化 Loader

對于 Loader 來說,影響打包效率首當其沖必屬 Babel 了。因為 Babel 會將代碼轉(zhuǎn)為字符串生成 AST,然后對 AST 繼續(xù)進行轉(zhuǎn)變最后再生成新的代碼,項目越大,轉(zhuǎn)換代碼越多,效率就越低。當然了,這是可以優(yōu)化的。

首先我們優(yōu)化 Loader 的文件搜索范圍

module.exports = {
  module: {
    rules: [
      {
        // js 文件才使用 babel
        test: /\.js$/,
        loader: 'babel-loader',
        // 只在 src 文件夾下查找
        include: [resolve('src')],
        // 不會去查找的路徑
        exclude: /node_modules/
      }
    ]
  }
}

對于 Babel 來說,希望只作用在 JS 代碼上的,然后 node_modules 中使用的代碼都是編譯過的,所以完全沒有必要再去處理一遍。

當然這樣做還不夠,還可以將 Babel 編譯過的文件緩存起來,下次只需要編譯更改過的代碼文件即可,這樣可以大幅度加快打包時間

loader: 'babel-loader?cacheDirectory=true'

(2)HappyPack

受限于 Node 是單線程運行的,所以 Webpack 在打包的過程中也是單線程的,特別是在執(zhí)行 Loader 的時候,長時間編譯的任務很多,這樣就會導致等待的情況。

HappyPack 可以將 Loader 的同步執(zhí)行轉(zhuǎn)換為并行的,這樣就能充分利用系統(tǒng)資源來加快打包效率了

module: {
  loaders: [
    {
      test: /\.js$/,
      include: [resolve('src')],
      exclude: /node_modules/,
      // id 后面的內(nèi)容對應下面
      loader: 'happypack/loader?id=happybabel'
    }
  ]
},
plugins: [
  new HappyPack({
    id: 'happybabel',
    loaders: ['babel-loader?cacheDirectory'],
    // 開啟 4 個線程
    threads: 4
  })
]

(3)DllPlugin

DllPlugin 可以將特定的類庫提前打包然后引入。這種方式可以極大的減少打包類庫的次數(shù),只有當類庫更新版本才有需要重新打包,并且也實現(xiàn)了將公共代碼抽離成單獨文件的優(yōu)化方案。DllPlugin的使用方法如下:

// 單獨配置在一個文件中
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
  entry: {
    // 想統(tǒng)一打包的類庫
    vendor: ['react']
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].dll.js',
    library: '[name]-[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      // name 必須和 output.library 一致
      name: '[name]-[hash]',
      // 該屬性需要與 DllReferencePlugin 中一致
      context: __dirname,
      path: path.join(__dirname, 'dist', '[name]-manifest.json')
    })
  ]
}

然后需要執(zhí)行這個配置文件生成依賴文件,接下來需要使用 DllReferencePlugin 將依賴文件引入項目中

// webpack.conf.js
module.exports = {
  // ...省略其他配置
  plugins: [
    new webpack.DllReferencePlugin({
      context: __dirname,
      // manifest 就是之前打包出來的 json 文件
      manifest: require('./dist/vendor-manifest.json'),
    })
  ]
}

(4)代碼壓縮

在 Webpack3 中,一般使用 UglifyJS 來壓縮代碼,但是這個是單線程運行的,為了加快效率,可以使用 webpack-parallel-uglify-plugin 來并行運行 UglifyJS,從而提高效率。

在 Webpack4 中,不需要以上這些操作了,只需要將 mode 設置為 production 就可以默認開啟以上功能。代碼壓縮也是我們必做的性能優(yōu)化方案,當然我們不止可以壓縮 JS 代碼,還可以壓縮 HTML、CSS 代碼,并且在壓縮 JS 代碼的過程中,我們還可以通過配置實現(xiàn)比如刪除 console.log 這類代碼的功能。

(5)其他

可以通過一些小的優(yōu)化點來加快打包速度

  • ?resolve.extensions?:用來表明文件后綴列表,默認查找順序是 ?['.js', '.json']?,如果你的導入文件沒有添加后綴就會按照這個順序查找文件。我們應該盡可能減少后綴列表長度,然后將出現(xiàn)頻率高的后綴排在前面
  • ?resolve.alias?:可以通過別名的方式來映射一個路徑,能讓 Webpack 更快找到路徑
  • ?module.noParse?:如果你確定一個文件下沒有其他依賴,就可以使用該屬性讓 Webpack 不掃描該文件,這種方式對于大型的類庫很有幫助

2. 如何減少 Webpack 打包體積

(1)按需加載

在開發(fā) SPA 項目的時候,項目中都會存在很多路由頁面。如果將這些頁面全部打包進一個 JS 文件的話,雖然將多個請求合并了,但是同樣也加載了很多并不需要的代碼,耗費了更長的時間。那么為了首頁能更快地呈現(xiàn)給用戶,希望首頁能加載的文件體積越小越好,這時候就可以使用按需加載,將每個路由頁面單獨打包為一個文件。當然不僅僅路由可以按需加載,對于 loadash 這種大型類庫同樣可以使用這個功能。

按需加載的代碼實現(xiàn)這里就不詳細展開了,因為鑒于用的框架不同,實現(xiàn)起來都是不一樣的。當然了,雖然他們的用法可能不同,但是底層的機制都是一樣的。都是當使用的時候再去下載對應文件,返回一個 Promise,當 Promise 成功以后去執(zhí)行回調(diào)。

(2)Scope Hoisting

Scope Hoisting 會分析出模塊之間的依賴關系,盡可能的把打包出來的模塊合并到一個函數(shù)中去。

比如希望打包兩個文件:

// test.js
export const a = 1
// index.js
import { a } from './test.js'

對于這種情況,打包出來的代碼會類似這樣:

[
  /* 0 */
  function (module, exports, require) {
    //...
  },
  /* 1 */
  function (module, exports, require) {
    //...
  }
]

但是如果使用 Scope Hoisting ,代碼就會盡可能的合并到一個函數(shù)中去,也就變成了這樣的類似代碼:

[
  /* 0 */
  function (module, exports, require) {
    //...
  }
]

這樣的打包方式生成的代碼明顯比之前的少多了。如果在 Webpack4 中你希望開啟這個功能,只需要啟用 optimization.concatenateModules 就可以了:

module.exports = {
  optimization: {
    concatenateModules: true
  }
}

(3)Tree Shaking

Tree Shaking 可以實現(xiàn)刪除項目中未被引用的代碼,比如:

// test.js
export const a = 1
export const b = 2
// index.js
import { a } from './test.js'

對于以上情況,test 文件中的變量 b 如果沒有在項目中使用到的話,就不會被打包到文件中。

如果使用 Webpack 4 的話,開啟生產(chǎn)環(huán)境就會自動啟動這個優(yōu)化功能。

3. 如何?webpack來優(yōu)化前端性能?

?webpack優(yōu)化前端性能是指優(yōu)化webpack的輸出結(jié)果,讓打包的最終結(jié)果在瀏覽器運?快速?效。

  • 壓縮代碼:刪除多余的代碼、注釋、簡化代碼的寫法等等?式。可以利?webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 來壓縮JS?件, 利? cssnano (css-loader?minimize)來壓縮css
  • 利?CDN加速: 在構(gòu)建過程中,將引?的靜態(tài)資源路徑修改為CDN上對應的路徑??梢岳?webpack對于 output 參數(shù)和各loader的 publicPath 參數(shù)來修改資源路徑
  • Tree Shaking: 將代碼中永遠不會?到的?段刪除掉??梢酝ㄟ^在啟動webpack時追加參數(shù) --optimize-minimize 來實現(xiàn)
  • Code Splitting: 將代碼按路由維度或者組件分塊(chunk),這樣做到按需加載,同時可以充分利?瀏覽器緩存
  • 提取公共第三?庫: SplitChunksPlugin插件來進?公共模塊抽取,利?瀏覽器緩存可以?期緩存這些?需頻繁變動的公共代碼

4. 如何提?webpack的構(gòu)建速度?

  1. 多??情況下,使? CommonsChunkPlugin 來提取公共代碼
  2. 通過 externals 配置來提取常?庫
  3. 利? DllPlugin 和 DllReferencePlugin 預編譯資源模塊 通過 DllPlugin 來對那些我們引?但是絕對不會修改的npm包來進?預編譯,再通過 DllReferencePlugin 將預編譯的模塊加載進來。
  4. 使? Happypack 實現(xiàn)多線程加速編譯
  5. 使? webpack-uglify-parallel 來提升 uglifyPlugin 的壓縮速度。 原理上 webpack-uglify-parallel 采?了多核并?壓縮來提升壓縮速度
  6. 使? Tree-shaking 和 Scope Hoisting 來剔除多余代碼


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號