你的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
请求得来的,包括 js
、css
、 图片等等,既然这些内容都需要请求,那我能不能在请求发出后,做一些处理呢?就像房东租房,房东与租客之间的信息可能是不对称的,这时中介出现了,它能够在房东出租房子之前做一些处理,比如加收中介费。网页在发起资源请求时,我们也可以做一些决定,是从缓存拿,还是去请求。而针对不同的资源,正是通过资源请求地址来实现的,这便是基于路由,示例如下
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 || []);
到这里,能想象通过我们对于项目中资源的配置,支持离线访问吗?通过这些配置能够极大提升应用性能,策略,你要的才是最美的。
我是合一,英雄再会!
- 老生常谈:利用Membership实现SSO(单点登录)
- nginx利用geo模块做限速白名单以及geo实现全局负载均衡的操作记录
- Mysql高效插入/更新数据
- 宋小菜融资2.3亿元!域名保护意识强
- 世界最奇葩的7款机器人
- Mysql高效插入/更新数据
- 关于Membership/Role您可能不知道的细节
- Sqlite向MySql导入数据
- 未来3年,人工智能如何影响法律行业?5位权威专家给出趋势
- Java 常见内存溢出异常与代码实现
- nginx限制上传大小和超时时间设置说明/php限制上传大小
- Unity Application Block 1.2 学习笔记
- 苹果首个自动驾驶专利到底有什么来头?
- 围棋遇上互联网:科技打开优秀传统文化未来之门
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SpringMVC源码学习(三) - 请求处理的流程
- Hadoop框架:集群模式下分布式环境搭建
- 微服务 Hystrix 实现服务熔断
- 微服务 Gateway 的基本配置
- 有赞营销逆向域的探索与实践
- RabbitMQ 启动报错:Error: unable to perform an operation on node ‘rabbit@***‘. Please see diagnostics...
- MySQL|查询字段数量多少对查询效率的影响
- 如果MySQL事务中发生了网络异常?
- MySQL|update字段为相同的值是否会记录binlog
- 微服务配置 Config 与消息总线
- 贷款违约预测-Task5 模型融合
- Python字符串
- MYSQL logstash 同步数据到es的几种方案对比以及每种方案数据丢失原因分析。
- 手写“SpringBoot”:几十行代码基于Netty搭建一个 HTTP Server
- SpringCloud Sleuth 分布式请求链路追踪