web前端進階篇(二) 瀏覽器 Webpack

a1322674015發表於2019-10-18

一、瀏覽器

1 cookie和localSrorage、session、indexDB 的區別

web前端進階篇(二) 瀏覽器 Webpack


從上表可以看到,cookie 已經不建議用於儲存。如果沒有大量資料儲存需求的話,可以使用 localStorage和 sessionStorage 。對於不怎麼改變的資料儘量使用 localStorage 儲存,否則可以用 sessionStorage 儲存。


對於 cookie,我們還需要注意安全性

web前端進階篇(二) 瀏覽器 Webpack


2 怎麼判斷頁面是否載入完成?

  • Load 事件觸發代表頁面中的 DOM,CSS,JS,圖片已經全部載入完畢。

  • DOMContentLoaded 事件觸發代表初始的 HTML 被完全載入和解析,不需要等待 CSS,JS,圖片載入

3 如何解決跨域

因為瀏覽器出於安全考慮,有同源策略。也就是說,如果協議、域名或者埠有一個不同就是跨域,Ajax請求會失敗。


我們可以透過以下幾種常用方法解決跨域的問題


JSONP


JSONP 的原理很簡單,就是利用


<script src="
<script>
    function jsonp(data) {
    console.log(data)
}
</script>

JSONP 使用簡單且相容性不錯,但是隻限於 get 請求


  • 在開發中可能會遇到多個 JSONP 請求的回撥函式名是相同的,這時候就需要自己封裝一個 JSONP,以下是簡單實現

function jsonp(url, jsonpCallback, success) {
  let script = document.createElement("script");
  script.src = url;
  script.async = true;
  script.type = "text/javascript";
  window[jsonpCallback] = function(data) {
    success && success(data);
  };
  document.body.appendChild(script);
}
jsonp(
  "
  "callback",
  function(value) {
    console.log(value);
  }
);



CORS


  • ORS需要瀏覽器和後端同時支援。IE 8 和 9 需要透過 XDomainRequest 來實現。

  • 瀏覽器會自動進行 CORS 通訊,實現CORS通訊的關鍵是後端。只要後端實現了 CORS,就實現了跨域。

  • 服務端設定 Access-Control-Allow-Origin 就可以開啟 CORS。 該屬性表示哪些域名可以訪問資源,如果設定萬用字元則表示所有網站都可以訪問資源。


document.domain


  • 該方式只能用於二級域名相同的情況下,比如 a.test.com 和 b.test.com 適用於該方式。

  • 只需要給頁面新增 document.domain = ‘test.com’ 表示二級域名都相同就可以實現跨域 


postMessage


這種方式通常用於獲取嵌入頁面中的第三方頁面資料。一個頁面傳送訊息,另一個頁面判斷來源並接收訊息


// 傳送訊息端
window.parent.postMessage('message', ');
// 接收訊息端
var mc = new MessageChannel();
mc.addEventListener('message', (event) => {
    var origin = event.origin || event.originalEvent.origin;
    if (origin === ') {
        console.log('驗證透過')
    }
});

4 什麼是事件代理

如果一個節點中的子節點是動態生成的,那麼子節點需要註冊事件的話應該註冊在父節點上


<ul id="ul">
<li>1</li>
    <li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
let ul = document.querySelector('#ul')
ul.addEventListener('click', (event) => {
console.log(event.target);
})
</script>
  • 事件代理的方式相對於直接給目標註冊事件來說,有以下優點

    • 節省記憶體

    • 不需要給子節點登出事件

5 Service worker

service worker

Service workers 本質上充當Web應用程式與瀏覽器之間的代理伺服器,也可以在網路可用時作為瀏覽器和網路間的代理。它們旨在(除其他之外)使得能夠建立有效的離線體驗,攔截網路請求並基於網路是否可用以及更新的資源是否駐留在伺服器上來採取適當的動作。他們還允許訪問推送通知和後臺同步API


目前該技術通常用來做快取檔案,提高首屏速度,可以試著來實現這個功能


// index.js
if (navigator.serviceWorker) {
  navigator.serviceWorker
    .register("sw.js")
    .then(function(registration) {
      console.log("service worker 註冊成功");
    })
    .catch(function(err) {
      console.log("servcie worker 註冊失敗");
    });
}
// sw.js
// 監聽 `install` 事件,回撥中快取所需檔案
self.addEventListener("install", e => {
  e.waitUntil(
    caches.open("my-cache").then(function(cache) {
      return cache.addAll(["./index.html", "./index.js"]);
    })
  );
});
// 攔截所有請求事件
// 如果快取中已經有請求的資料就直接用快取,否則去請求資料
self.addEventListener("fetch", e => {
  e.respondWith(
    caches.match(e.request).then(function(response) {
      if (response) {
        return response;
      }
      console.log("fetch source");
    })
  );
});

開啟頁面,可以在開發者工具中的 Application 看到 Service Worker已經啟動了


6 瀏覽器快取

快取對於前端效能最佳化來說是個很重要的點,良好的快取策略可以降低資源的重複載入提高網頁的整體載入速度。


  • 通常瀏覽器快取策略分為兩種:強快取和協商快取。


強快取

實現強快取可以透過兩種響應頭實現:Expires 和 Cache-Control 。強快取表示在快取期間不需要請求,state code 為200


Expires: Wed, 22 Oct 2018 08:41:00 GMT



Expires 是 HTTP / 1.0 的產物,表示資源會在Wed,22 Oct 2018 08:41:00 GMT 後過期,需要再次請求。並且 Expires 受限於本地時間,如果修改了本地時間,可能會造成快取失效。


Cache-control: max-age=30



  • Cache-Control 出現於 HTTP / 1.1,優先順序高於 Expires 。該屬性表示資源會在 30 秒後過期,需要再次請求。


協商快取


  • 如果快取過期了,我們就可以使用協商快取來解決問題。協商快取需要請求,如果快取有效會返回 304。

  • 協商快取需要客戶端和服務端共同實現,和強快取一樣,也有兩種實現方式


Last-Modified 和 If-Modified-Since


  • Last-Modified表示本地檔案最後修改日期,If-Modified-Since 會將 Last-Modified 的值傳送給伺服器,詢問伺服器在該日期後資源是否有更新,有更新的話就會將新的資源傳送回來。

  • 但是如果在本地開啟快取檔案,就會造成 Last-Modified被修改,所以在 HTTP / 1.1 出現了 ETag


ETag 和 If-None-Match


ETag 類似於檔案指紋,If-None-Match 會將當前 ETag傳送給伺服器,詢問該資源 ETag 是否變動,有變動的話就將新的資源傳送回來。並且 ETag 優先順序比 Last-Modified 高


選擇合適的快取策略


對於大部分的場景都可以使用強快取配合協商快取解決,但是在一些特殊的地方可能需要選擇特殊的快取策略


  • 對於某些不需要快取的資源,可以使用 Cache-control: no-store ,表示該資源不需要快取

  • 對於頻繁變動的資源,可以使用 Cache-Control: no-cache並配合 ETag 使用,表示該資源已被快取,但是每次都會傳送請求詢問資源是否更新。

  • 對於程式碼檔案來說,通常使用 Cache-Control: max-age=31536000 並配合策略快取使用,然後對檔案進行指紋處理,一旦檔名變動就會立刻下載新的檔案

7 瀏覽器效能問題


重繪(Repaint)和迴流(Reflow)


  • 重繪和迴流是渲染步驟中的一小節,但是這兩個步驟對於效能影響很大。

  • 重繪是當節點需要更改外觀而不會影響佈局的,比如改變 color就叫稱為重繪

  • 迴流是佈局或者幾何屬性需要改變就稱為迴流。

  • 迴流必定會發生重繪,重繪不一定會引發迴流。迴流所需的成本比重繪高的多,改變深層次的節點很可能導致父節點的一系列迴流。


所以以下幾個動作可能會導致效能問題:


  • 改變 window 大小

  • 改變字型

  • 新增或刪除樣式

  • 文字改變

  • 定位或者浮動

  • 盒模型


很多人不知道的是,重繪和迴流其實和 Event loop 有關。


  • 當 Event loop 執行完 Microtasks後,會判斷 document 是否需要更新。- 因為瀏覽器是 60Hz 的重新整理率,每 16ms才會更新一次。

  • 然後判斷是否有resize 或者 scroll ,有的話會去觸發事件,所以 resize 和 scroll 事件也是至少 16ms 才會觸發一次,並且自帶節流功能。

  • 判斷是否觸發了 media query

  • 更新動畫並且傳送事件

  • 判斷是否有全屏操作事件

  • 執行 requestAnimationFrame回撥

  • 執行 IntersectionObserver 回撥,該方法用於判斷元素是否可見,可以用於懶載入上,但是相容性不好

  • 更新介面

  • 以上就是一幀中可能會做的事情。如果在一幀中有空閒時間,就會去執行 requestIdleCallback 回撥。


減少重繪和迴流


使用 translate 替代 top


<div class="test"></div>
<style>
.test {
position: absolute;
top: 10px;
width: 100px;
height: 100px;
background: red;
}
</style>
<script>
setTimeout(() => {
        // 引起迴流
document.querySelector('.test').style.top = '100px'
}, 1000)
</script>
  • 使用 visibility 替換 display: none ,因為前者只會引起重繪,後者會引發迴流(改變了佈局)

  • 把 DOM 離線後修改,比如:先把 DOM 給 display:none(有一次 Reflow),然後你修改100次,然後再把它顯示出來

  • 不要把 DOM結點的屬性值放在一個迴圈裡當成迴圈裡的變數

for(let i = 0; i < 1000; i++) {
    // 獲取 offsetTop 會導致迴流,因為需要去獲取正確的值
    console.log(document.querySelector('.test').style.offsetTop)
}


  • 不要使用 table 佈局,可能很小的一個小改動會造成整個 table 的重新佈局 動畫實現的速度的選擇,動畫速度越快,迴流次數越多,也可以選擇使用 requestAnimationFrame

  • CSS選擇符從右往左匹配查詢,避免 DOM 深度過深

  • 將頻繁執行的動畫變為圖層,圖層能夠阻止該節點回流影響別的元素。比如對於 video 標籤,瀏覽器會自動將該節點變為圖層。


CDN


靜態資源儘量使用 CDN 載入,由於瀏覽器對於單個域名有併發請求上限,可以考慮使用多個 CDN 域名。對於 CDN 載入靜態資源需要注意 CDN 域名要與主站不同,否則每次請求都會帶上主站的 Cookie


使用 Webpack 最佳化專案


  • 對於 Webpack4,打包專案使用 production 模式,這樣會自動開啟程式碼壓縮

  • 使用 ES6 模組來開啟 tree shaking,這個技術可以移除沒有使用的程式碼

  • 最佳化圖片,對於小圖可以使用 base64 的方式寫入檔案中

  • 按照路由拆分程式碼,實現按需載入

三、Webpack

1 最佳化打包速度

  • 減少檔案搜尋範圍 

    • 比如透過別名

    • loader 的 test,include & exclude

  • Webpack4 預設壓縮並行

  • Happypack 併發呼叫

  • babel 也可以快取編譯

2 Babel 原理

  • 本質就是編譯器,當程式碼轉為字串生成 AST,對 AST 進行轉變最後再生成新的程式碼

  • 分為三步:詞法分析生成 Token,語法分析生成 AST,遍歷 AST,根據外掛變換相應的節點,最後把 AST轉換為程式碼

3 如何實現一個外掛

  • 呼叫外掛 apply 函式傳入 compiler 物件

  • 透過 compiler 物件監聽事件

比如你想實現一個編譯結束退出命令的外掛

apply (compiler) {
  const afterEmit = (compilation, cb) => {
    cb()
    setTimeout(function () {
      process.exit(0)
    }, 1000)
  }
  compiler.plugin('after-emit', afterEmit)
}
}
module.exports = BuildEndPlugin

幫助我們改善此頁面!

————————————————

版權宣告:本文為CSDN博主「活波的小白羊」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結及本宣告。

原文連結:https://blog.csdn.net/qq_21118431/article/details/102613470


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946034/viewspace-2660587/,如需轉載,請註明出處,否則將追究法律責任。

相關文章