专栏首页JavaScript全栈你的web应用支持离线访问和策略缓存吗?

你的web应用支持离线访问和策略缓存吗?

沉醉在生命的优美。看着星,想象你自己跟它们在奔驰。——哲学家,马克·奥勒留

•微信公众号 《JavaScript全栈》•掘金 《合一大师》•Bilibili 《合一大师

性能始终在时间与空间上相互权衡取舍,计算机系统的优化需要借助各种缓存策略,从CPU到内存,从接口到外设。如果有一天,硬件成本和实现难度不再是阻碍,也许便没有了“优化”这个字眼。

当下,前端面临的优化与挑战更多,复杂的终端环境,各种不同的浏览器内核,尺寸不一的浏览设备,兼容要做。复杂不稳定的网络环境,越来越多的资源,优化要做。对于缓存,我们并不陌生,但是我们想有主观意识的缓存,我想缓存什么,缓存多久,缓存和请求资源的策略是什么都有自己来定,service worker 能帮我们做到。

使用 service worker 前,需要创建一份注册文件,不妨在项目下创建一个名为 sw.js 的文件

console.log('Hello, I am sw.js file')

然后在应用中通过这个文件进行注册,通过以下代码就能完成应用中 service worker 的注册,后面关于 service worker 相关的处理,在 sw.js 文件中进行。

<script>
    // 检查当前浏览器是否支持service workers
  if ('serviceWorker' in navigator) {
    // 确保资源加载完成,再注册service worker
    window.addEventListener('load', () => {
      navigator.serviceWorker.register('/sw.js');
    });
  }
</script>

刷新页面,就能看到控制台打印了这句话,表示 service worker 注册成功

打开控制台 Application ,一切在掌控之中, service worker 注册成功

到这里完成了,完成了 service worker 的注册,关于其相关的配置和处理,我们一起去 sw.js 文件中定义吧!

Google推出的、标准统一api操作的、基于 service worker 的策略缓存库,它有以下几点让人称赞的特点

1.Precaching2.Runtime caching3.Strategies4.Request routing5.Background sync6.Helpful debuggin7.Greater flexibility and feature set than sw-precache and sw-toolbox

我想起了一句话,简单的概念复杂化,通俗的概念神秘化,这是为了展示自己的不凡,?,开个玩笑。相信大多人看到这些概念是蒙的,我们只需要围绕一个概念:缓存 ,并且是策略性的,存什么是可以控制的,也给我们开发离线应用提供了思路。

使用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 || []);

到这里,能想象通过我们对于项目中资源的配置,支持离线访问吗?通过这些配置能够极大提升应用性能,策略,你要的才是最美的。

我是合一,英雄再会!

本文分享自微信公众号 - JavaScript全栈(gh_0a40552e913e),作者:合一

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 每日两题 T1

    有两个容量分别为 x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?

    合一大师
  • 每日两题 T4

    一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找...

    合一大师
  • 每日两题 T37

    一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

    合一大师
  • AR游戏《哈利波特:巫师联盟》将于7月上线,用“魔法”击败魔物

    VRPinea
  • 这个996.icu,恐怕是说出了上万名程序猿工作背后的心酸

    在2019年3月26日,有人在Github上注册了一个名为“996icu”的不知名小号,仅仅为一篇“readme”的控诉,引起了IT业界的一场轩然大波。

    23号杂货铺
  • springboot实战之总结篇

    springboot实战系列暂时先更新到这边,下边是对之前springboot实战文章做一个汇总

    lyb-geek
  • 网页打开速度的心理学

    所以,没有访问者真的能够忍受一个打开速度极慢的网站。但是,网页打开速度到底对用户行为有什么影响,恐怕没几个人能够说清楚吧。

    ruanyf
  • Golang 单元测试框架 gocheck 使用介绍

    单元测试应该在的功能和参数上验证程序的正确性;单元测试过后,机器状态应该保持不变;单元测试的运行、通过、失败不依赖于别的测试,可以人为构造数据,以保持单元测试的...

    李海彬
  • Web前端学习 第6章 jQuery Ajax 4 跨域请求

    同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以xyz.com下的js脚本采用ajax读取abc.com里面的文...

    学习猿地
  • 【融职培训】Web前端学习 第6章 jQuery Ajax 4 跨域请求

    同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。所以xyz.com下的js脚本采用ajax读取abc.com里面的文...

    学习猿地

扫码关注云+社区

领取腾讯云代金券