页面守护者:Service Worker

1. Service Worker的身份

Service的意思是服务,Worker的意思是工人,那么Service Worker的意思就是服务员。这个员工是2014年6月HTML5新招的实习生,目前在试用中。在此之前,已经有一位老员工,它叫Web Worker。那么问题来了,Boss是谁?Boss就是浏览器。准确来说,每个页面的javascript运行主线程都是一个Boss。

这里先谈一下大的背景。Boss很厉害,在页面上指点江山,呼风唤雨。但他有个局限:同一时刻只做一件事(单线程)。当一些很耗时的杂事让Boss去处理时,在处理的过程中他就无暇顾及其它重要的事了。在用户看来,页面没人管了,Boss不干事了!这时Boss就很郁闷。为了保证Boss能处理更重要的事情,董事会(W3C)终于招聘了一个新员工:Web worker。这下,Boss终于可以从耗时的杂事中解放出来了,他只需要把Web worker叫过来说:“这些事情拿去做,没做完不要来找我”。Web worker领到任务后默默地到自己的工位(线程)去干活,完成之后给Boss发了个邮件(postMessage)。Boss收到邮件(onmessage)后欣慰地点了点头。

扯了半天好像还没谈到新员工啊。。。不急,下面就讲到了。

Boss下班了(页面关闭),Web worker也收拾东西回家了。这样执行了很久,直至2014年6月,董事会发现一个问题:“居然没有人在老板下班后加班?”。于是,又招了一个专职加班的:Service Worker。它被赋予的绩效目标如下:

  1. 入职(install)后永不下班,而能更新。
  2. 能处理Boss需要的资源(HTTPS请求),以便离线时也能让BOSS取到数据(从cache中)。
  3. 能向客户推送消息(push notifications)
  4. 不允许越权管理Boss的事(DOM ACCESS)

总地来说,Service worker是独立于页面的一个运行环境,它在页面关闭后仍可以运行。同时,也能对它负责的页面的网络请求进行截取和返回请求(类似于Fiddler)。

2. 使用条件

  • 请求协议条件 HTTPS。 毕竟给Service Worker的权利较大,可以直接截取和返回用户的请求,所以了于安全考虑,目前只能在HTTPS环境下才能使用Service Worker。
  • 浏览器支持

目前支持的浏览器不多,而且支持的浏览器也是在试验阶段。3. 一个栗子 下面的例子将展示通过Service Worker来实现一个离线页面,在第一次访问后,后续即使没有网络连接,也能从缓存中获取页面必要的资源。例子源自github上一个demo

  • 页面文件代码:
<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Service Worker offline demo</title>
    <style>
        body {
            background-image: url("./images/background.jpeg");/*背景图片*/
        }
    </style>
</head>
<body>

<div>Learn Web Design &amp; Development with SitePoint tutorials, 
courses and books - HTML5, CSS3, JavaScript, PHP, mobile app development, Responsive Web Design</div>
<script>
    if (navigator.serviceWorker) {
        // 注册Service Worker scope表示作用的页面的path
        // register函数返回Promise
        navigator.serviceWorker.register('./service-worker.js', {scope: './'}) 
            .then(function (registration) {
                console.log(registration);
            })
            .catch(function (e) {
                console.error(e);
            })
    } else {
        console.log('Service Worker is not supported in this browser.')
    }
</script>
</body>
</html>
  • Service Worker文件:service-worker.js
importScripts('js/cache-polyfill.js'); // cache 扩展

var CACHE_VERSION = 'app-v1'; // 缓存文件的版本
var CACHE_FILES = [ // 需要缓存的页面文件
    '/',
    'images/background.jpeg',
    'js/app.js',
    'css/styles.css'
];


self.addEventListener('install', function (event) { // 监听worker的install事件
    event.waitUntil( // 延迟install事件直到缓存初始化完成
        caches.open(CACHE_VERSION)
            .then(function (cache) {
                console.log('Opened cache');
                return cache.addAll(CACHE_FILES);
            })
    );
});

self.addEventListener('activate', function (event) { // 监听worker的activate事件
    event.waitUntil( // 延迟activate事件直到
        caches.keys().then(function(keys){
            return Promise.all(keys.map(function(key, i){ // 清除旧版本缓存
                if(key !== CACHE_VERSION){
                    return caches.delete(keys[i]);
                }
            }))
        })
    )
});

self.addEventListener('fetch', function (event) { // 截取页面的资源请求
    event.respondWith( // 返回页面的资源请求
        caches.match(event.request).then(function(res){ // 判断缓存是否命中
            if(res){  // 返回缓存中的资源
                return res;
            }
            requestBackend(event); // 执行请求备份操作
        })
    )
});

function requestBackend(event){  // 请求备份操作
    var url = event.request.clone();
    return fetch(url).then(function(res){ // 请求线上资源
        //if not a valid response send the error
        if(!res || res.status !== 200 || res.type !== 'basic'){
            return res;
        }

        var response = res.clone();

        caches.open(CACHE_VERSION).then(function(cache){ // 缓存从线上获取的资源
            cache.put(event.request, response);
        });

        return res;
    })
}
  • Service Worker生命周期

Service Worder在安装(install)和激活(activate)后,会进入正常工作状态。当它负责的页面在浏览器中被打开,它就会对页面的请求进行处理。在其它情况下(除了特殊情况:service worker会定时更新),Service worker处理暂停状态,不会占用内存和CPU资源。

  • 例子运行效果

上图为在第一次打开页面后,关闭网络,再次打开的页面请求。页面在离线情况下仍然能打开,并且能获取到相应的样式和脚本资源。从图中可以看出,资源的获取途径是“from ServiceWorker”,说明确实是serviceWorker在起作用了。

4. 开启chrome隐藏技能

chrome上有三个与service Worker相关的调试和查看工具

  • 1 看正在运行的 serivce worker:chrome://inspect/#service-workers
  • 2 ervice Worker调试(查看console.log输出,也可注销worker)
  • 3 藏的Resources查看选项,开启步骤如下: 1 进入 chrome://flags 开启 ‘Enable DevTools Experiments’. 2 打开DevTools, 进入 Setting > Experiments , 连续按shift键6下 3 在DevTools的Resources页面里就能看到刚被开启的隐藏功能:

5. 总结

Service Worker是继web Worker后又一个新的线程,这个线程比web worker独立得更彻底,可以在页面没有打开的时候就运行。作为一个页面与服务器之间中间层,Service Worker可以捕获它所负责的页面的请求,并返回相应资源,这使离线web应用成为了可能。这也是Service Worker被提出的一个重要目的。虽然现在支持的浏览器和平台还不多,而且还在试验阶段,但已被W3C制定规范。在将来,当Service Worker更成熟和普及时,将会为web app打开新的大门。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

用 Python 搞定正方教务系统之抢课篇

最近学校开始选课,但是如果选课时间与自己的事情冲突,这时候就可以使用Python脚本自助抢课,抢课的第一步即是模拟登录,需要模拟登录后保存登录信息然后再进行操作...

2430
来自专栏FreeBuf

Tunnel:论如何在内网中自由渗透

*本文作者:戒贤,本文属FreeBuf原创奖励计划,未经许可禁止转载 背景 能够成功地通过web漏洞获取到webshell,对于一次完整的渗透测试来说,仅仅相当...

26610
来自专栏开源项目

2017 JavaScript 开发者的学习图谱 | 码云周刊第 25 期

码云项目推荐 1前端框架类 1. 基于 Vue.js 的 UI 组件库 iView ? 项目简介:iView 是一套基于 Vue.js 的 UI 组件库,主要服...

3297
来自专栏逸鹏说道

Uncaught RangeError: Maximum call stack size exceeded 调试日记

异常处理汇总-前端系列 http://www.cnblogs.com/dunitian/p/4523015.html 开发道路上不是解决问题最重要,而是解决问题...

3208
来自专栏信安之路

记一次线下赛靶机攻击过程

咋一眼看过去除了 80 端口的 web 以为就没其他端口了,尝试着进行全端口扫描发现,还是一样。

740
来自专栏北京马哥教育

5个最佳免费Linux杀毒软件

Linux的防病毒软件,开玩笑吧?Linux不是很安全吗?很多Linux新手都这样认为,看到标题不要犹豫,读完全文你就会从中找到答案。 首先,Linux比其它操...

5826
来自专栏安恒信息

大量Windows 0-day漏洞泄漏,安恒信息提供免费在线检测

北京时间 2017 年 4 月 14 日晚,黑客团体Shadow Brokers(影子经纪人)再次泄露了一份 117.9 MB 的 NSA 机密文档,内含 23...

2485
来自专栏张戈的专栏

SEO养博客神器:同步文章(或摘要)到新浪博客的WordPress插件

了解 SEO 的站长都会另外用心做几个博客,起到 SEO 辅助作用。通常说的养博客主要是养 BSP 博客。比如新浪博客,网易博客,百度空间,网易博客,新浪博客,...

4066
来自专栏玄魂工作室

[实战]如何在Kali Linux中进行WIFI钓鱼?

文中提及的部分技术可能带有一定攻击性,仅供安全学习和教学用途,禁止非法使用! ? 0x00 实验环境 操作系统:Kali 1.0 (VM) FackAP: ea...

4216
来自专栏pangguoming

最火的Android开源项目整理

一、代码库 1、from  代码家 整理比较好的源码连接 ***************************************************...

5934

扫码关注云+社区