你的web應用支持離線訪問和策略緩存嗎?

沉醉在生命的優美。看着星,想象你本身跟它們在奔馳。——哲學家,馬克·奧勒留javascript

  • 微信公衆號 《JavaScript全棧
  • 掘金 《合一大師
  • Bilibili 《合一大師

性能始終在時間與空間上相互權衡取捨,計算機系統的優化須要藉助各類緩存策略,從CPU到內存,從接口到外設。若是有一天,硬件成本和實現難度再也不是阻礙,也許便沒有了「優化」這個字眼。css

當下,前端面臨的優化與挑戰更多,複雜的終端環境,各類不一樣的瀏覽器內核,尺寸不一的瀏覽設備,兼容要作。複雜不穩定的網絡環境,愈來愈多的資源,優化要作。對於緩存,咱們並不陌生,可是咱們想有主觀意識的緩存,我想緩存什麼,緩存多久,緩存和請求資源的策略是什麼都有本身來定,service worker 能幫咱們作到。html

使用 service worker 前,須要建立一份註冊文件,不妨在項目下建立一個名爲 sw.js 的文件前端

console.log('Hello, I am sw.js file')
複製代碼

而後在應用中經過這個文件進行註冊,經過如下代碼就能完成應用中 service worker 的註冊,後面關於 service worker 相關的處理,在 sw.js 文件中進行java

<script> // 檢查當前瀏覽器是否支持service workers if ('serviceWorker' in navigator) { // 確保資源加載完成,再註冊service worker window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js'); }); } </script>
複製代碼

刷新頁面,就能看到控制檯打印了這句話,表示 service worker 註冊成功webpack

打開控制檯 Application ,一切在掌控之中, service worker 註冊成功web

到這裏完成了,完成了 service worker 的註冊,關於其相關的配置和處理,咱們一塊兒去 sw.js 文件中定義吧!正則表達式

Google推出的、標準統一api操做的、基於 service worker 的策略緩存庫,它有一下幾點讓人稱讚的特色npm

  1. Precaching
  2. Runtime caching
  3. Strategies
  4. Request routing
  5. Background sync
  6. Helpful debuggin
  7. Greater flexibility and feature set than sw-precache and sw-toolbox

我想起了一句話,簡單的概念複雜化,通俗的概念神祕化,這是爲了展現本身的不凡,😆,開個玩笑。相信大多人看到這些概念是蒙的,咱們只須要圍繞一個概念:緩存 ,而且是策略性的,存什麼是能夠控制的,也給咱們開發離線應用提供了思路。api

使用Workbox

還記得那個 sw.js 文件嗎?如今咱們把中心放在它身上,由於後續相關的操做要在這個文件中進行,ready?go!

###導入Workbox

首先在 sw.js 第一行導入 workbox.js 語法以下

importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
複製代碼

這樣就導入成功了嗎?寫段代碼測試一下吧!

if (workbox) {
  console.log(`Yay! Workbox is loaded 🎉`);
} else {
  console.log(`Boo! Workbox didn't load 😬`);
}
複製代碼

更改完成後,回到瀏覽器,此時刷新瀏覽器沒有任何變化,這裏須要提醒一點,更改完 service worker 註冊文件須要終止重啓或者更新。

開始使用Workbox

Workbox 定義了標準統一API,咱們來看如何藉助它提供的API逐步優化項目

路由請求定義緩存

Workbox 中,最核心的概念要數基於路由的策略緩存了,這裏抓住兩個關鍵詞,基於路由策略 。接下來的重點即是放在如何基於路由,如何體現策略。

前端的大多資源都是經過 HTTP 請求得來的,包括 jscss 、 圖片等等,既然這些內容都須要請求,那我能不能在請求發出後,作一些處理呢?就像房東租房,房東與租客之間的信息多是不對稱的,這時中介出現了,它可以在房東出租房子以前作一些處理,好比加收中介費。網頁在發起資源請求時,咱們也能夠作一些決定,是從緩存拿,仍是去請求。而針對不一樣的資源,正是經過資源請求地址來實現的,這即是__基於路由__,示例以下

workbox.routing.registerRoute(
  /\.js$/,
  …
);
複製代碼

以上代碼咱們定義了一個路由緩存策略,即:全部後綴爲 .js 的請求都會進入該策略進行處理,那,咱們須要作什麼處理呢?就會有針對匹配該路由的資源定義不一樣的關於緩存的策略,好比,咱們要求指定資源 網絡請求優先

workbox.routing.registerRoute(
  /\.js$/,
  new workbox.strategies.NetworkFirst()
);
複製代碼

此時若是在項目中引入了js文件,這個緩存便會生效,假設項目引入 hello.js

console.log('hello js file')
複製代碼

在html中引入

<script src="./hello.js"></script>
複製代碼

來到瀏覽器首先update一下service worker,方法上面介紹過這裏不贅述。緊接着刷新,咱們能夠看到打印的日誌,說明配置成功

萬事開頭難,咱們已經克服這第一道難題了,接下來先橫向拓展,針對不一樣類型文件的配置,選用不一樣策略。咱們先來看處理不一樣文件的配置,很簡單

字符串方式
workbox.routing.registerRoute(
    '/logo.png',
    handler // handler 是作緩存策略的回調函數,一般指後面所會降到的 '緩存策略函數'
);
workbox.routing.registerRoute(
    'https://some-host/some-path/logo.png',
    handler
);
複製代碼
正則表達式
workbox.routing.registerRoute(
  // 緩存圖片.
  /\.(?:png|jpg|jpeg|svg|gif)$/,
  handler
);
複製代碼
函數形式
// 經過函數來匹配請求路由
const matchFunction = ({url, event}) => {
    // 若是請求路由匹配了就返回 true,也能夠返回一個參數對象以供 handler 接收處理
    return false;
};

workbox.routing.registerRoute(
    matchFunction,
    handler
);
複製代碼

上面代碼的handler是workbox提供的緩存策略API,經常使用的有如下幾種

策略名 API
staleWhileRevalidate 當請求的路由有對應的 Cache 緩存結果就直接返回,在返回 Cache 緩存結果的同時會在後臺發起網絡請求拿到請求結果並更新 Cache 緩存,若是原本就沒有 Cache 緩存的話,直接就發起網絡請求並返回結果
networkFirst 網絡優先的策略
cacheFirst 直接從 Cache 緩存中取得結果,若是 Cache 緩存中沒有結果,那就會發起網絡請求,拿到網絡請求結果並將結果更新至 Cache 緩存,並將結果返回給客戶端
networkOnly 強制使用正常的網絡請求
cacheOnly 直接使用 Cache 緩存的結果

通常場景下,以上5種策略基本能知足要求,若是還有不知足的狀況,可自定義策略

workbox.routing.registerRoute(
    ({url, event}) => {
        return {
            name: 'workbox'
        };
    },
    ({url, event, params}) => {
        // 返回的結果是:A guide on workbox
        return new Response(
            `I am ${params.name}`
        );
    }
);
複製代碼

如下給出一個示例,介紹不一樣策略的使用方法

例如,圖片類資源,由於不太常更改,因此能夠選用優先緩存策略,併爲該類資源分組,具體內容能夠在 Application -> Cache 查看

workbox.routing.registerRoute(
  /\.(?:png|jpg|jpeg|svg|gif)$/,
  new workbox.strategies.CacheFirst({
    cacheName: 'my-image-cache',
  })
);
複製代碼

js等相關文件能夠適當選擇網絡優先

workbox.routing.registerRoute(
  /\.html$/,
  new workbox.strategies.NetworkFirst()
);

workbox.routing.registerRoute(
  /\.js$/,
  new workbox.strategies.NetworkFirst({
    networkTimeoutSeconds: 3,
  })
);
複製代碼

webpack中使用workbox

首先安裝 workbox-webpack-plugin ,選擇使用npm安裝

npm install --save-dev workbox-webpack-plugin
複製代碼

在webpack配置文件中配置該插件

const workboxPlugin = require('workbox-webpack-plugin');

// ...
webpack({
    plugins: [
        // ...
        new workboxPlugin({
            swSrc: './src/sw.js',
            swDest: './dist/sw.js',
            globDirectory: './dist/',
            globPatterns: ['**/*.{html,js,css}'],
        })
    ]
    // ...
});
複製代碼

使用 workbox 提供的 Webpack 插件必須在 app/sw.js 中包含如下代碼才能完成預緩存內容列表注入工做

workbox.precaching.precacheAndRoute(self.__precacheManifest || []);
複製代碼

到這裏,能想象經過咱們對於項目中資源的配置,支持離線訪問嗎?經過這些配置可以極大提高應用性能,策略,你要的纔是最美的。

我是合一,英雄再會!

相關文章
相關標籤/搜索