使用Service Worker优选请求资源 - 持续更新

前言

长期更新请看我的个人博客,因为我没法在那么多的平台同步更新 https://blog.imlete.cn/article/Service-Worker-Preferred-Request-Resource.html

当你的网站或博客有多个部署点时,部署在某个平台的访问速度比较快,于是你就把你的域名解析到了这个平台上,但有时候还是会变得很慢,这时其它站点速度可能会变得比你当前使用的还快一点,难道还有来回解析域名吗?太麻烦了

有没有可以直接返回最快网站资源的办法呢?

  1. 使用域名管理平台,有些平台可以解析不同网络或地区的站点
    例如腾讯云可以区分解析国内三大运营商、境内、境外、等一些解析选项(不太好用,还需要自己测试,难不成求使用其它运营商手机的朋友帮你测一下快不快嘛~)
  2. 使用 js 拦截网站的所有请求,并篡改将请求发送到自己的所有站点,这些站点中如果哪个站点最快返回,那么就用最快返回的这个信息,与此同时将其它的请求全部切断

正文

本文会详细说明如何使用 Service Worker 优选请求资源让你的网站比以前更快,更稳定

Service Worker在接下来的内容中统一称呼为sw

Service Worker

更详细请看https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API

Service workers 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器

Service worker 运行在 worker 上下文,因此它不能访问 DOM。相对于驱动应用的主 JavaScript 线程,它运行在其他线程中,所以不会造成阻塞。

出于安全考量,Service workers 只能由 HTTPS 承载,毕竟修改网络请求的能力暴露给中间人攻击会非常危险。

注册

注册 sw 很简单,只需一行代码即可,如果注册成功,则 sw 会被下载到客户端并且安装和激活,这一步仅仅是注册而已,完整的是: 下载—>安装—>激活

注意: sw 的注册日志记录在 Chrome 浏览器中可以通过访问chrome://serviceworker-internals查看

navigator.serviceWorker.register('/Service-Worker.js')

其中/Service-Worker.js必须是当前域下的 js 文件,他不能是其它域下的,即使 js 文件内的内容完全相等,那也不行

如果你只想在某个路径写使用 sw 的话,你可以使用scope选项,当然/Service-Worker.js的位置也可以自定义(只要是同源且是 https 协议就可以),如下只有在/article/文章页 sw 才启动,其它路径写 sw 不进行处理

navigator.serviceWorker.register('/sw-test/Service-Worker.js', {
    scope: '/article/' })

并且必须是 https 协议,如果是本地127.0.0.1localhost是被允许的

这是一个完整的注册代码

将安装代码放置在<head>之后

<script>
  ;(function () {
     
    if ('serviceWorker' in navigator) {
     
      navigator.serviceWorker
        .register('/sw.js')
        .then((result) => {
     
          // 判断是否安装了sw
          if (!localStorage.getItem('installSW')) {
     
            localStorage.setItem('installSW', true)
            // 这里就不用清理setInterval了,因为页面刷新后就没有了
            setInterval(() => {
     
              // 判断sw安装后,是否处于激活状态,激活后刷新页面
              if (result && result.active && result.active.state === 'activated') {
     
                location.reload()
              }
            }, 100)
          }
        })
        .catch((err) => {
     
          console.log(err)
        })
    }
  })()
</script>

生命周期

installing 状态

当注册成功后会触发install事件,然后触发activate事件,此时如果再次刷新页面,它俩都不会被触发了

直到/sw.js发生了改变,它就会触发一次 install (不仅仅是代码改变,哪怕是多一个空格或是少一个空格,又或是写一个注释都会被触发),但是只执行了install事件,并没有执行activate事件

activing 状态

为什么activate事件不触发了?因为已经有一个 sw 了,它一种处于等待状态,至于什么时候才会被触发,那就是等之前的 sw 停止了才会触发activate事件

那有没有办法不让它等待呢?答案是:

使用skipWaiting()跳过等待,它返回一个 promise 对象(异步的),防止还在执行skipWaiting()的时候直接就跳到activate事件,我们需要使用async/await,也可以使用event.waitUntil(skipWaiting())方法把skipWaiting()放到里面,和async/await效果一样

// sw.js

// 在sw中可以使用this或是self表示自身
self.addEventListener('install', async (event) => {
   
  // event.waitUntil(self.skipWaiting())
  await self.skipWaiting()
})

触发activate事件后 ,当前这一次网页是不会被 sw 管理的,需要下次页面刷新才会被 sw 管理,那怎么让它立即管理页面呢?

更详细请看:
https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/skipWaiting
https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim


                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值