Service Worker 圖片加載失敗處理

Service Worker 圖片加載失敗處理

參考文檔html

git clone https://gitee.com/wjj0720/Service-Worker.git
運行 npm i 
npm start
訪問 http://127.0.0.1:3000/pages/index.html  

打開控制檯  刷新(因爲demo作的是後加載 需刷新後 看效果)

ctrl + c 結束node服務 再次刷新頁面(從緩存裏面讀取 依然顯示頁面)

簡介

  • 背景node

    有一個困擾 web 用戶多年的難題——丟失網絡鏈接。以前的嘗試 — AppCache — 看起來是個不錯的方法,可是,它假定你使用時會遵循諸多規則,若是你不嚴格遵循這些規則,它會把你的APP搞得一團糟。Service worker 最終要去解決這些問題。雖然 Service Worker 的語法比 AppCache 更加複雜,可是你可使用 JavaScript 更加精細地控制 AppCache 的靜默行爲。有了它,你能夠解決目前離線應用的問題,同時也能夠作更多的事。 Service Worker 可使你的應用先訪問本地緩存資源,因此在離線狀態時,在沒有經過網絡接收到更多的數據前,仍能夠提供基本的功能(通常稱之爲 Offline First)。這是原生APP 原本就支持的功能,這也是相比於 web app,原生 app 更受青睞的主要緣由。
  • 什麼是Service Worker ?git

    Service Worker是瀏覽器在後臺啓動的一條服務Worker線程
  • 功能和特性:github

    1.一個獨立的 worker 線程,且只有一個。
      2.一旦被 install,就永遠存在,除非被 uninstall
      3.須要的時候能夠直接喚醒,不須要的時候自動睡眠(此處有坑)
      4.可代理請求和返回,緩存文件,緩存的文件能夠被網頁進程取到
      5.能向客戶端推送消息
      6.不能直接操做 DOM
      7.出於安全的考慮,必須在 HTTPS/localhost  環境下才能工做
      8.異步實現,內部大都是經過 Promise 實現
      9.基於[web worker](http://www.ruanyifeng.com/blog/2018/07/web-worker.html)

使用

  • 1.註冊web

    // 兼容判斷
       if ("serviceWorker" in navigator) {
        // 通常考慮加載問題 windoe.onload後加載
        window.addEventListener("load", function() {
          // scope 參數是選填的,能夠被用來指定你想讓 service worker 控制的內容的子目錄
          navigator.serviceWorker.register("/sw.js", {scope: '/'})
            .then(function(registration) {
              // 註冊成功
              console.log( "ServiceWorker registration successful with scope: ", registration.scope )
            })
            .catch(function(err) {
              // 註冊失敗
              console.log("ServiceWorker registration failed: ", err)
            });
        })
      }
    • 2.使用npm

      const precacheVersion = 2
          const precacheName = "precache-v" + precacheVersion
        
          var precacheFiles = [
            "/pages/index.html",
            "/images/dmx.jpg",
            "/images/broken.png"
          ]
      
      
      /*更新
       *  SW.js 瀏覽器會自動檢查差別性 
       * 發生變動 install 事件被觸發 此時,舊的 SW 還在工做,新的 SW 進入 waiting 狀態。
       * 注意,此時並不存在替換接管,當你如今已經打開的頁面關閉時,那麼舊的 SW 則會被 kill 掉。
       * 新的 SW 就開始接管頁面的緩存資源。 一旦新的 SW 接管,則會觸發 activate 事件。 
      */
      
      self.addEventListener("install", e => {
        console.log("[ServiceWorker] Installed")
      // skipWaiting() 方法跳過 waiting 狀態,而後會直接進入 activate 階段
        self.skipWaiting()
      
        e.waitUntil(
          caches.open(precacheName).then(cache => {
            // 若是其中有一個 加載失敗 那就表明着--此次啓動 GG  
            return cache.addAll(precacheFiles)
      
            // cache.put(request, response).then(function() {
            //   // 成功緩存
            // });
          })
        ) 
      })
      
      self.addEventListener("activate", e => {
        console.log("[ServiceWorker] Activated")
      
        e.waitUntil(
          caches.keys().then(cacheNames => {
            return Promise.all(
              cacheNames.map(thisCacheName => {
                if ( thisCacheName.includes("precache") && thisCacheName !== precacheName ) {
                  return caches.delete(thisCacheName)
                }
              })
            )
          })
        )
      
        // 更新客戶端
        // self.clients.claim()
      
      })
      
      
      // 監聽頁面的請求 (不單單是js請求)
      self.addEventListener("fetch", e => {
        e.respondWith(
          caches.match(e.request).then(response => {
            // 有緩存走緩存
            if (response) {
              return response
            }
      
            return fetch(e.request) .then(fetchResponse => {
      
              // console.log('s-->', fetchResponse);
              if (fetchResponse.ok) return fetchResponse;
              // 加載失敗的狀況下 入股是圖片 則返回默認圖片
              if (isImage(e.request)) {
                return returnBrokenImg()
              }
      
              
            }).catch(err => {
              if ( isImage(e.request) ) {
                return returnBrokenImg()
              }
            })
          })
        )
      })
      
      function isImage(fetchRequest) {
        return fetchRequest.method === "GET" && fetchRequest.destination === "image";
      }
      
      function returnBrokenImg () {
        return caches.match('/images/broken.png').then(response => response)
      }
      
      
      // 監聽頁面發來的消息
      self.addEventListener('message', function (message, e) {
        console.log('service接受到的數據--->', message, e);
        sendMessageToPage('嘟嘟嘟')
      });
      
      // 向頁面發送消息
      function sendMessageToPage (msg) {
      
        self.clients.matchAll().then(function (clients) {
          if (clients && clients.length) {
            clients.forEach(function (client) {
              client.postMessage(msg);
            })
          }
        })
      }
    • 3.客戶端更新瀏覽器

      除了由瀏覽器觸發更新以外,若是24小時沒有更新,會強制更新。這意味着最壞狀況下Service Worker會天天更新一次
      //客戶端更新方法: localStorage 存下 版本  運行時候對比
        var version = 'precache-v3'
        navigator.serviceWorker.register('/sw.js').then(function (reg) {
          if (localStorage.getItem('sw_version') !== version) {
            reg.update().then(function () {
              localStorage.setItem('sw_version', version)
            });
          }
        })
    • 4.客戶端消息緩存

      // 監聽serviceWorker 消息
        navigator.serviceWorker.addEventListener('message', function (event) {
            // 接受數據,
            console.log('頁面接受的數據:',  event);
        });
        // 發送消息
        document.getElementById('sendMSG').addEventListener('click', function () {
            console.log('綁定點擊事件,點擊後發送數據');
            navigator.serviceWorker.controller.postMessage('嘀嘀嘀');
        });
      1. 應用案例
      1. 攔截圖片加載失敗 返回默認圖片 案例 https://bitsofco.de/handling-broken-images-with-service-worker/
        2. 藍湖 https://lanhuapp.com/

新鮮貨

  1. https://github.com/jiahaog/na...
  2. https://imgcook.taobao.org/pr...
相關文章
相關標籤/搜索