likes
comments
collection
share

Service Worker【JS深入知识汇点10】

作者站长头像
站长
· 阅读数 0

对于web应用,掉线不能使用是理所应当的,如果我们希望支持离线,service worker 出现的目的是让 web app 可以和 native app 开始真正意义上的竞争

Service Worker 是浏览器在后台独立于网页运行的脚本,它打开了通向不需要网页或用户交互的功能的大门。现在,它们已经包括如推送通知和后台同步等功能。我们主要讨论的核心功能是拦截和处理网络请求,包括通过程序来管理缓存中的响应,

Service Worker 使用条件

平常浏览器窗口跑的是主 JS 线程,而 Service Worker 是走的另外的线程,因此,和浏览器页面的进程不会有任何影响,

由于Service Worker 是完全异步,同步 api (比如 XHR 和 localStrage)不能在它里面使用。

必须满足以下条件才可以使用:

  • 用https:为了避免中间人可能用于不良目的,可仅在通过 https 提供的页面上注册 Service Worker。不过,在http://localhost 或者 http://127.0.0.1这种本地环境也可以跑起来
  • 现在Chrome、FireFox 和 Opera 支持它

Service Worker 生命周期

  1. 为网站安装服务工作线程:先在页面的 JS 中注册,注册服务工作线程将会导致浏览器在后台启动服务工作线程安装步骤

    // 注册,这将告诉浏览器 Service Worker JavaScript 文件的位置
    if ('serviceWorker' in navigator) {
    	window.addEventListener('load', function() {
        	//register 精妙之处在于文件的位置,如果是/eg/sw.js,则意味着服务工作线程的作用域是网址/eg/开头的页面
        	navigator.serviceWorker.register('/sw.js').then((registration) => {
            	console.log('ServiceWorker registration successful with scope:', registration.scope)
            }, (err) => {
            	console.log('ServiceWorker registration failed: ', err)
            })
        })
    }
    
  2. 安装过程中,缓存某些静态资源,如果所有文件已缓存成功,那么 Service Worker 就安装完毕。如果任何文件失败,那么安装步骤会失败,它下次会再试一次

    var CACHE_NAME = 'my-site-cache-v1';
    var urlsToCache = [
    	'/',
        '/styles/main.css',
        '/script/main.js'
    ]
    self.addEventListener('install', (event) => {
    	// 确认所有需要的资产是否已缓存
        event.waitUntil(
        	// 打开缓存
        	caches.open(CACHE_NAME)
            .then((cache) => {
            	// 缓存文件
                return cache.addAll(urlsToCache)
            })
        );
        
    })
    
  3. 激活

  4. Service Worker 会对其作用域内的所有页面实施控制,开始接收 fetch 事件。

self.addEventListener('fetch', (event) => {
	event.respondWith(
    	caches.match(event.request)
        	.then((response) => {
            	if(response) {
                	return response
                }
                //调用 fetch 发出网络请求
                return fetch(event.request)
            })
    )
})

Service Worker 更新

当需要更新 Service Worker 时,需要遵循以下步骤:

  1. 更新 JS 文件,浏览器会尝试在后台重新下载定义 Service Worker 的脚本文件,如果与当前的存在字节差异,将其视为新 Service Worker
  2. 新的 Service Worker 会启动,并触发 install 事件
  3. 新的 Service Worker 进入 waiting 状态
  4. 当网站上当前打开的页面关闭,旧 Service Worker 会被终止,新 Service Worker 会取得控制权
  5. 新 Service Worker 取得控制权后,将会触发其 activate 事件
self.addEventListener('activate', (event) => {
	var cacheAllowlist = ['pages-cache-v1', 'blog-posts-chache-v1']
    event.waitUntil(
    	caches.keys().then((cacheNames) => {
        	return Promise.all(
            	cacheNames.map(item => {
                	if (cacheAllowlist.indexOf(cacheName) === -1) {
                    	return caches.delete(cacheName)
                    }
                })
            )
        })
    )
})

和 PWA 技术关系

PWA 全称为 “Progressive Web Apps”,渐进式网页应用。

PWA 的核心技术包括:

  • Web App Manifest - 在主屏幕添加 app 图标,定义手机标题栏颜色之类
  • Service Worker - 缓存,离线开发,以及地理位置信息处理等
  • App Shell - 先显示 APP 的主结构,再填充主数据
  • Push Notification - 消息推送

可以看出来,Service Worker 是 PWA 技术的一部分,但是又独立于 PWA。也就是,虽然 PWA 技术面向移动端,但是不影响我们在桌面端渐进使用 Service Worker 。

Service Worker 应用

  • 后台数据同步
  • 响应来自其它源的资源请求
  • 集中接收计算成本高的数据更新,比如地理位置和陀螺仪信息,这样多个页面可以用同一组数据
  • 性能增强,比如预取用户可能需要的资源

好题分享

Q1:什么是 PWA ?

PWA 就是 渐进式网页应用,谷歌在 2015 年提出的概念,在外观和感觉上和 原生app 类似。支持 PWA 的网站可以提供脱机工作、推送通知和设备硬件访问等功能,

Q2:PWA 有哪些优点? - 更小更快,比原生app小的多,没有浪费磁盘空间,所以加载速度非常快 - 响应式界面:支持网页自动适应各种屏幕大小 - 无需更新:总是加载最新版本 - 高性价比:原生 App 开发需要分别为 Android 和 iOS 设备开发,开发成本很高 - SEO优势:引擎可恶意发现 PWA,并且加载速度非常快。 - 脱机功能:service worker Api的支持 - 安全性: 通过https连接传递,并在每次交互中保护用户数据 - 推送通知:通过推送通知的支持,PWA 非常轻松地与用户进行交互,提供很棒的用户体验 - 绕过应用商店 - 零安装

Q3: PWA 有什么缺点? - 对系统功能的访问权限较低 - 没有审查标准:缺乏从应用程序商店中获取推广利益

Q4: 如果让一个 web 应用变成 PWA?

有以下原则需要遵守:

  • 可发现的,内容可以通过搜索引擎找到
  • 可安装,可以在设备的主屏幕上使用
  • 可链接,可以通过 URL 来分享它
  • 与网络无关,可以在离线或网络连接不好的情况下工作
  • 渐进式的,可以在老浏览器上使用
  • 可重新参与。能发送通知,每当有新的内容可用
  • 安全
  • 可响应

Q5: PWA 和 Hybrid 之间有什么不同?

Hybrid 是指使用 web 和原生技术的组合构建的应用程序,这些程序通过应用商店发布,要经过苹果、谷歌、微软等的商店审核

Q6: 什么是 App Shell ?

App Shell 架构是构建 PWA 的一种方式,这种应用能可靠且即时地加载到用户屏幕上。