资讯专栏INFORMATION COLUMN

ServiceWorker系列——ServiceWorker生命周期

raledong / 1406人阅读

摘要:再次修改控制台输出也就是说激活过程中的任何错误不影响被激活脑洞下新激活过程中说明页面已经没有被其他控制了,所以事件回调函数的执行失败并不会影响被激活。

ServiceWorker生命周期

ServiceWorker本身是有状态的(installing,installed,activating,activated,redundant),这些状态构成了ServiceWorker生命周期:

生命周期可细分为两个过程:

安装过程(installing,installed)

激活过程(activating, activated)

1. installing

当使用方法navigator.serviceWorker.register注册一个新的ServiceWorker时,浏览器会下载JS脚本,解析脚本。这时ServiceWorker处于installing状态。如果安装成功,则进入installed状态,否则会进入redundant状态。

1.1 InstallEvent对象

处于installing时会触发ServiceWorkerGlobalScope上下文的install事件。
index.html:




    Service Life Cycle
    




sw.js 文件内容:

self.addEventListener("install", function(event) {
    console.log("install callback")
})

可通过registration.installing属性访问处于install状态的ServiceWorker;

ServiceWorkerGlobalScope中可以绑定多个install事件回调函数,多个事件回调函数的参数是同一个InstallEvent对象;

如果install事件回调函数抛异常,则视为安装失败,ServiceWorker会进入redundant状态;

如果回调函数里调用installEvent.waitUntil(promise1)方法,则promise1被resolved时ServiceWorker对象才被installed,如果promise1被rejected则SW安装失败(redundant);

同一个事件回调函数或者多个事件回调函数可以多次调用installEvent.waitUntil(promise)方法,则表达所有的promise都被resolved时SW对象才被installed,只要存在promise被rejected则SW安装失败(redundant)。

修改sw.js内容,重新注册sw:

self.addEventListener("install", function(event) {
    event._from = "callback1"
    console.log("install callback 1: " + (Date.now()/1000))
    var i = 0;
    while(i < 1000000) {
        ++i;
    }
    // 多次调用
    event.waitUntil(new Promise(function(resolve) {
        setTimeout(() => {
            console.log("resolve 2s")
            resolve()
        }, 2000)
    }))
    event.waitUntil(new Promise(function(resolve, reject) {
        setTimeout(() => {
            console.log("resolve 3s")
            resolve() // 
        }, 3000)
    }))
})

// 多次绑定Install事件
self.addEventListener("install", function(event) {
    event._from = "callback2"
    console.log("install callback 2: " + (Date.now()/1000))
    event.waitUntil(new Promise(function(resolve) {
        setTimeout(() => {
            console.log("resolve 5s")
            resolve()
        }, 5000)
    }))
})

观察控制台输出

1.2 waitUntil方法

InstallEvent对象从父对象ExtendableEvent继承了waitUntil方法。该方法延长了事件对象的生存期。当传给waitUntil方法的Promise对象转成终态(resolved/rejected)才认为事件对象被处理完了。在事件对象被处理完之前ServiceWorker不会进入下一个状态(installed或者redundant)。

2. installed/waiting

ServiceWorker成功安装后便进入installed状态。至此Service完成了安装过程,等待进入激活过程

可通过registration.waiting属性访问处于installed状态的ServiceWorker(见上例);

如果页面没有激活的ServiceWorker管理,则ServiceWorker进入activating状态。

3. activating

ServiceWoker安装成功后进入activating状态。

3.1 ActivateEvent对象

处于activating时会触发ServiceWorkerGlobalScope上下文的activate事件。

可以绑定多个事件回调函数,多个事件回调ActivateEvent对象是同一个对象;

如果回调函数里调用activateEvent.waitUntil(promise1)方法,则表示promise1被resolved/rejected时SW对象才进入下一个状态activated

同一个事件回调函数或者多个事件回调函数可以多次调用activateEvent.waitUntil(promise)方法,则表达所有的promise都被resolved/rejected时SW对象才进入下一个状态activated
修改sw.js文件:

self.addEventListener("activate", function(event) {
    event._from = "callback1"
    console.log("activate callback 1: " + (Date.now()/1000))
    var i = 0;
    while(i < 1000000) {
        ++i;
    }
    event.waitUntil(new Promise(function(resolve, reject) {
        setTimeout(() => {
            console.log("resolve 2s")
            resolve()
        }, 2000)
    }))
    event.waitUntil(new Promise(function(resolve, reject) {
        setTimeout(() => {
            console.log("resolve 4s")
            resolve()
        }, 4000)
    }))
})

self.addEventListener("activate", (event) => {
    event.waitUntil(new Promise((resolve, reject) =>{
        setTimeout(() => {
            resolve("resolve activate")
        }, 5000)
    }))
})

控制台输出:

install事件回调函数不一样的是在activate事件回调函数里抛异常,或者传给activateEvent.waitUntil(promise1)方法的promise被reject都不会影响ServiceWorker进入activated状态。
再次修改sw.js:

self.addEventListener("activate", function(event) {
    event._from = "callback1"
    console.log("activate callback 1: " + (Date.now()/1000))
    var i = 0;
    while(i < 1000000) {
        ++i;
    }
    event.waitUntil(new Promise(function(resolve, reject) {
        setTimeout(() => {
            console.log("resolve 2s")
            resolve()
        }, 2000)
    }))
    event.waitUntil(new Promise(function(resolve, reject) {
        setTimeout(() => {
            console.log("resolve 4s")
            resolve()
        }, 4000)
    }))
})

self.addEventListener("activate", (event) => {
    throw "error"
    event.waitUntil(new Promise((resolve, reject) =>{
        setTimeout(() => {
            resolve("reject activate")
        }, 1)
    }))
})

self.addEventListener("activate", (event) => {
    event.waitUntil(new Promise((resolve, reject) =>{
        setTimeout(() => {
            reject("reject activate")
        }, 5000)
    }))
})

控制台输出:

也就是说激活过程中的任何错误不影响ServiceWoker被激活(脑洞下:新SW激活过程中说明页面已经没有被其他SW控制了,所以activate事件回调函数的执行失败并不会影响SW被激活。),注意这一点跟其他文档描述的可能不太一样。

4. activated

这时ServiceWorker可以控制页面了,可以监听功能事件了,如fetch,push事件。默认情况下ServiceWorker只能控制在其激活成功后才加载完成的页面。

4.1 fetch事件 & FetchEvent对象

ServiceWorker控制页面后就可以监听fetch事件了: 捕获请求,构建响应。注意:保证一个请求只有一个响应

可以绑定多个fetch事件,并且多个回调函数的fetchEvent是同一个对象;

如果回调函数内成功调用了fetchEvent.respondWith方法,则后面的回调函数不会被执行;

回调函数里多次调用fetchEvent.respondWith会报错的,即一个request只能有一个reponse

回调函数里最好是同步的方式调用fetchEvent.respondWith,异步调用不会阻止后面的后调函数执行, 很容易会造成多个reponse,导致错误3;

如果所有的回调函数里都没有调用fetchEvent.respondWith方法则会采用浏览器默认的fetch事件回调函数处理方式,即走网络请求;

fetch回调函数还可以调用waitUntil方法,来延长FetchEvent事件对象的生命,如果有FetchEent对象还未处理完浏览器是不会自动关闭SW的。

5. redundant

redundant状态是ServiceWorker的终态。 关于serviceWorker如何变成redundant状态在Lavas Service Worker 生命周期和 the-service-worker-lifecycle参考中列举了3种,但是测试发现激活失败并不会导致哎,见上例。在这本书里Building Progressive Web Apps by Tal Ater的观点貌似论证了我们代码。这里再汇总下进入redundant的case:

register失败,如多次调用register,后调用注册的SW会变成redundant

安装失败

被新版本的ServiceWorker替换

再强调下激活过程不会导致ServiceWorker变成redundant状态。

参考

Google 服务工作线程生命周期

Chapter 4. Service Worker Lifecycle and Cache Management

The Service Worker Lifecycle

Lavas Service Worker 生命周期

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99296.html

相关文章

  • pwa 实战总结

    摘要:现在表示公开支持。一旦安装完成,如果注册的没有变化,则显示为已激活的生命周期结束。一旦安装这步完成,便会激活,并控制在其范围内的一切。目前还在草案状态,仅火狐和谷歌浏览器支持此特性。 PWA初探 什么是PWA PWA(Progressive Web Apps):渐进式 Web app PWA 旨在增强 Web 体验,能让用户在访问一个web的时候感觉在使用app一样。 PWA可以看作是...

    xioqua 评论0 收藏0
  • serviceWorker 入门

    前提 本文涉及几个知识点:fetch、caches、indexDB 等都不会详细介绍,仅对于其中某些点带过 一. 概念 serviceWorker,服务工作线程,顾名思义,只是作为工作线程存在,不掺和到JS主线程中来,介于 浏览器 & 服务器中间层,可拦截指定 client 所发起的所有请求 二. 用途 目前 PWA(Progress Web App) 的概念很火,大致就是让 web 也跟 app...

    lemanli 评论0 收藏0
  • 使用offline-plugin搭配webpack轻松实现PWA

    摘要:配合的项,能够实现缓存外部资源的功能。允许接受来自的消息,默认值为。检查新版本的的更新信息。这也是我在研究阶段直接使用时所发现的问题。建议仅在生产模式内使用。 showImg(https://segmentfault.com/img/bVSVG1?w=1178&h=484); 谈起PWA,许多人可能还只停留在了解的层面,比较少在实践中真正地尝试过,更多的仅仅是对着网上的教程和例子大概玩...

    shadajin 评论0 收藏0
  • js构建离线应用

    摘要:技术实现离线应用的核心是离线缓存技术,历史上曾先后出现两种离线缓存技术。新的线程取得控制权后,将会触发其事件。接入用构建接入的离线应用时,要解决的问题在于如何生成之前提到的文件。 内容主要引用自吴浩麟著《webpack深入浅出》 离线应用 离线应用的优点: 在没有网络的情况下能打开网页。 由于部分缓存的资源直接从本地加载,所以对用户来说可以加快网页的加载速度,减少服务器压力。 技术实...

    phoenixsky 评论0 收藏0
  • 构建离线web应用(一)

    摘要:我喜欢移动,而且也是那些坚持使用技术构建移动应用程序的人之一。我们准备做这样的一个渐进式应用是典型的旨在提高用户离线体验的应用。当我们开始构建应用时,你就能理解上面的场景了。的作用范围是针对相对路径的。最佳的做法是在应用的入口。 我喜欢移动app,而且也是那些坚持使用Web技术构建移动应用程序的人之一。 经过技术的不断迭代(可能还有一些其它的东西),移动体验设计愈来愈平易近人,给予用户...

    Sanchi 评论0 收藏0

发表评论

0条评论

raledong

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<