沉醉在生命的优美。看着星,想象你自己跟它们在奔驰。——哲学家,马克·奥勒留
•微信公众号 《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
我想起了一句话,简单的概念复杂化,通俗的概念神秘化,这是为了展示自己的不凡,?,开个玩笑。相信大多人看到这些概念是蒙的,我们只需要围绕一个概念:缓存 ,并且是策略性的,存什么是可以控制的,也给我们开发离线应用提供了思路。
还记得那个 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
定义了标准统一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,
})
);
首先安装 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全栈 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!