连不上网,入门教程

Service Worker初体验

2016/01/06 · JavaScript
· Service Worker

初稿出处: AlloyTeam   

在二零一四年,W3C发布了service worker的草案,service
worker提供了诸多新的力量,使得web app拥有与native
app相同的离线体验、音讯推送体验。
service worker是一段脚本,与web
worker一样,也是在后台运行。作为一个独门的线程,运行环境与一般脚本差距,所以无法间接加入web交互行为。native
app能够形成离线使用、音信推送、后台自动更新,service
worker的产出是幸亏为了使得web app也足以拥有类似的力量。

 

service worker可以:

  1. 后台信息传递
  2. 网络代理,转载呼吁,伪造响应
  3. 离线缓存
  4. 新闻推送
  5.  … …

本文以资源缓存为例,表明一(Wissu)下service worker是咋办事的。

连不上网?英国卫报的个性离线页面是如此做的

2015/11/20 · HTML5 · Service
Worker,
离线页面

本文由 伯乐在线 –
Erucy
翻译,weavewillg
校稿。未经许可,禁止转发!
英文出处:Oliver
Ash。欢迎参与翻译组。

咱俩是什么样拔取 service worker 来为 theguardian.com
构建一个自定义的离线页面。

亚洲必赢官网 1

theguardian.com 的离线页面。插图:奥利弗 Ash

你正在朝着公司途中的大巴里,在小叔子大上开拓了
Guardian
应用。大巴被隧道包围着,不过那几个利用可以健康运行,即便没有网络连接,你也能赢得完整的意义,除了出示的情节可能有点旧。若是你品尝在网站上也这么干,可惜它完全无法加载:

亚洲必赢官网 2

安卓版 Chrome 的离线页面

Chrome 中的那一个彩蛋,很多少人都不驾驭》

Chrome
在离线页面上有个暗藏的游戏(桌面版上按空格键,手机版上点击那只恐龙),那有点能减轻一点您的干扰。不过大家可以做得更好。

Service
workers
允许网站小编拦截自己站点的具备网络请求,那也就意味着大家得以提供完善的离线体验,似乎原生应用相同。在
Guardian
网站,大家近年来上线了一个自定义的离线体验效果。当用户离线的时候,他们会晤到一个带有
Guardian
标识的页面,下边带有一个不难的离线提醒,还有一个填字游戏,他们得以在守候网络连接的时候玩玩那些找点乐子。那篇博客解释了俺们是什么构建它的,但是在起来从前,你能够先自己摸索看。

Service Worker入门

2015/03/26 · JavaScript
· Service Worker

原文出处: Matt
Gaunt连不上网,入门教程。   译文出处:[w3ctech

  • 十年踪迹]()   

原生App拥有Web应用一般所不负有的富离线体验,定时的敦默寡言更新,音讯布告推送等职能。而新的瑟维斯(Service)(Service)workers标准让在Web App上富有那几个作用成为可能。

渐进式Web应用(PWA)入门教程(下)

2018/05/25 · 基本功技术 ·
PWA

初稿出处: Craig
Buckler   译文出处:葡萄城控件   

上篇小说大家对渐进式Web应用(PWA)做了有的中央的牵线。

渐进式Web应用(PWA)入门教程(上)

在这一节中,大家将介绍PWA的规律是何许,它是什么开始工作的。

生命周期

先来看一下一个service worker的运转周期

亚洲必赢官网 3
上图是service
worker生命周期,出处

图中得以见到,一个service worker要经历以下进度:

  1.  安装

2.
 激活,激活成功以后,打开chrome://inspect/#service-workers可以查看到当下运行的service
worker

亚洲必赢官网 4

  1. 监听fetch和message事件,下边三种事件会开展简易描述

  2. 销毁,是不是销毁由浏览器决定,即使一个service
    worker短期不应用或者机器内存有数,则可能会销毁这一个worker

试试看

你须要一个支撑 Service
Worker 和 fetch
API 的浏览器。甘休到本文编写时只有Chrome(手机版和桌面版)同时协理那三种 API(译者注:Opera
方今也支撑那两边),不过 Firefox
很快就要帮助了(在天天更新的本子中已经支撑了),而外 Safari
之外的装有浏览器也都在摸索。此外,service worker 只可以登记在应用了
HTTPS 的网站上,theguardian.com
已经起来逐步搬迁到 HTTPS,所以我们只能在网站的 HTTPS
部分提供离线体验。就现阶段来说,我们选择了 开发者博客 作为我们用来测试的地点。所以如若您是在大家网站的 开发者博客 部分阅读那篇作品的话,很幸运。

当你利用协理的浏览器访问大家的 开发者博客 中的页面的时候,一切就准备妥当了。断开你的网络连接,然后刷新一下页面。即使你协调没规范尝试的话,可以看一下那段 演示视频(译者注:需梯子)。

Service Worker 是什么?

一个 service worker
是一段运行在浏览器后台进度里的本子,它独立于当下页面,提供了那几个不需要与web页面交互的意义在网页背后悄悄执行的力量。在今天,基于它能够兑现音信推送,静默更新以及地理围栏等服务,可是近来它首先要所有的功效是挡住和拍卖网络请求,包罗可编程的响应缓存管理。

怎么说那几个API是一个尤其棒的API呢?因为它使得开发者可以支撑更加好的离线体验,它赋予开发者完全控制离线数据的能力。

在service worker提议以前,其余一个提供开发者离线体验的API叫做App
Cache。然则App
Cache有些局限性,例如它可以很不难地化解单页应用的问题,可是在多页应用上会很麻烦,而Serviceworkers的出现正是为了化解App Cache的痛点。

下边详细说一下service worker有啥样须求留意的地点:

  • 它是JavaScript
    Worker,所以它无法一贯操作DOM。可是service
    worker可以通过postMessage与页面之间通讯,把新闻布告给页面,尽管需求的话,让页面自己去操作DOM。
  • Serviceworker是一个可编程的网络代理,允许开发者控制页面上拍卖的网络请求。
  • 在不被利用的时候,它会融洽终止,而当它再也被用到的时候,会被重新激活,所以你不可以凭借于service
    worker的onfecth和onmessage的处理函数中的全局状态。假设你想要保存一些持久化的音讯,你能够在service
    worker里使用IndexedDB API。
  • Serviceworker多量使用promise,所以借使您不打听如何是promise,那你必要先读书这篇文章。

第一步:使用HTTPS

渐进式Web应用程序必要采用HTTPS连接。固然选拔HTTPS会让你服务器的支付变多,但使用HTTPS可以让您的网站变得更安全,HTTPS网站在谷歌(Google)上的排行也会更靠前。

是因为Chrome浏览器会默许将localhost以及127.x.x.x地点视为测试地点,所以在本示例中您并不必要开启HTTPS。其余,出于调试目标,您可以在启动Chrome浏览器的时候利用以下参数来关闭其对网站HTTPS的检讨:

  • –user-data-dir
  • –unsafety-treat-insecure-origin-as-secure

fetch事件

在页面发起http请求时,service
worker可以通过fetch事件拦截请求,并且付诸自己的响应。
w3c提供了一个新的fetch
api,用于代替XMLHttpRequest,与XMLHttpRequest最大差异有两点:

1.
fetch()方法重返的是Promise对象,通过then方法举办两次三番调用,裁减嵌套。ES6的Promise在成为业内未来,会越来越方便开发人士。

2. 提供了Request、Response对象,尽管做过后端开发,对Request、Response应该相比精晓。前端要倡导呼吁可以透过url发起,也足以采纳Request对象发起,而且Request可以复用。但是Response用在哪个地方吗?在service
worker出现以前,前端确实不会融洽给协调发信息,可是有了service
worker,就足以在阻碍请求之后据悉需求发回自己的响应,对页面而言,那一个普通的伏乞结果并没有区分,那是Response的一处选择。

上面是在中,小编运用fetch
api通过fliker的公开api获取图片的例证,注释中详细解释了每一步的法力:

JavaScript

/* 由于是get请求,直接把参数作为query string传递了 */ var URL =
”;
function fetchDemo() { // fetch(url,
option)辅助七个参数,option中得以设置header、body、method音信fetch(URL).then(function(response) { // 通过promise
对象获得相应内容,并且将响应内容依照json格式转成对象,json()方法调用之后回来的仍旧是promise对象
// 也足以把内容转化成arraybuffer、blob对象 return response.json();
}).then(function(json) { // 渲染页面 insertPhotos(json); }); }
fetchDemo();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 由于是get请求,直接把参数作为query string传递了 */
var URL = ‘https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=your_api_key&format=json&nojsoncallback=1&tags=penguins’;
 
function fetchDemo() {
  // fetch(url, option)支持两个参数,option中可以设置header、body、method信息
  fetch(URL).then(function(response) {
    // 通过promise 对象获得相应内容,并且将响应内容按照json格式转成对象,json()方法调用之后返回的依然是promise对象
    // 也可以把内容转化成arraybuffer、blob对象
    return response.json();
  }).then(function(json) {
    // 渲染页面
    insertPhotos(json);
  });
}
 
fetchDemo();

fetch
api与XMLHttpRequest相比较,越发简明,并且提供的功力更周密,资源获取格局比ajax更优雅。包容性方面:chrome
42上马协助,对于旧浏览器,可以透过官方维护的polyfill辅助。

做事规律

通过一段简单的
JavaScript,大家得以提醒浏览器在用户访问页面的时候立时登记大家温馨的
service worker。方今支撑 service worker
的浏览器很少,所以为了避免不当,大家要求运用特性检测。

JavaScript

if (navigator.serviceWorker) {
navigator.serviceWorker.register(‘/service-worker.js’); }

1
2
3
if (navigator.serviceWorker) {
    navigator.serviceWorker.register(‘/service-worker.js’);
}

Service(Service) worker
安装事件的一局部,大家得以应用 新的缓存
API 来缓存大家网站中的各类内容,比如
HTML、CSS 和
JavaScript:

JavaScript

var staticCacheName = ‘static’; var version = 1; function updateCache()
{ return caches.open(staticCacheName + version) .then(function (cache) {
return cache.addAll([ ‘/offline-page.html’, ‘/assets/css/main.css’,
‘/assets/js/main.js’ ]); }); }; self.addEventListener(‘install’,
function (event) { event.waitUntil(updateCache()); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var staticCacheName = ‘static’;
var version = 1;
 
function updateCache() {
    return caches.open(staticCacheName + version)
        .then(function (cache) {
            return cache.addAll([
                ‘/offline-page.html’,
                ‘/assets/css/main.css’,
                ‘/assets/js/main.js’
            ]);
        });
};
 
self.addEventListener(‘install’, function (event) {
    event.waitUntil(updateCache());
});

当安装已毕后,service worker
可以监听和决定 fetch
事件,让大家得以完全控制之后网站中发出的兼具网络请求。

JavaScript

self.addEventListener(‘fetch’, function (event) {
event.respondWith(fetch(event.request)); });

1
2
3
self.addEventListener(‘fetch’, function (event) {
    event.respondWith(fetch(event.request));
});

在那边大家有很利索的上空能够表明,比如上边这几个典型,能够通过代码来生成大家团结一心的伸手响应:

JavaScript

self.addEventListener(‘fetch’, function (event) { var response = new
Response(‘<h1>Hello, World!</h1>’, { headers: {
‘Content-Type’: ‘text/html’ } }); event.respondWith(response); });

1
2
3
4
5
self.addEventListener(‘fetch’, function (event) {
    var response = new Response(‘&lt;h1&gt;Hello, World!&lt;/h1&gt;’,
        { headers: { ‘Content-Type’: ‘text/html’ } });
    event.respondWith(response);
});

再有那个,倘若在缓存中找到了请求相应的缓存,大家得以一向从缓存中回到它,即使没找到的话,再通过网络获取响应内容:

JavaScript

self.addEventListener(‘fetch’, function (event) { event.respondWith(
caches.match(event.request) .then(function (response) { return response
|| fetch(event.request); }) ); });

1
2
3
4
5
6
7
8
self.addEventListener(‘fetch’, function (event) {
    event.respondWith(
        caches.match(event.request)
            .then(function (response) {
                return response || fetch(event.request);
            })
    );
});

那么大家怎么着使用那一个意义来提供离线体验吧?

首先,在 service worker
安装进度中,大家要求把离线页面要求的 HTML 和资源文件通过 service worker
缓存下来。在缓存中,我们加载了温馨开销的 填字游戏 的
React应用 页面。之后,我们会阻拦所有访问
theguardian.com
网络请求,蕴含网页、以及页面中的资源文件。处理这个请求的逻辑大概如下:

  1. 当大家检测到传播请求是指向大家的 HTML
    页面时,大家连年会想要提供最新的情节,所以大家会尝试把那么些请求通过网络发送给服务器。

    1. 当大家从服务器得到了响应,就可以直接回到那一个响应。
    2. 如若网络请求抛出了尤其(比如因为用户掉线了),大家捕获那些丰裕,然后使用缓存的离线
      HTML 页面作为响应内容。
  2. 不然,当大家检测到请求的不是 HTML
    的话,大家会从缓存中找找响应的呼吁内容。

    1. 比方找到了缓存内容,大家可以直接重临缓存的情节。
    2. 否则,大家会尝试把这些请求通过网络发送给服务器。

在代码中,大家运用了 新的缓存
API(它是 Service(Service) Worker API 的一有的)以及
fetch
功用(用于转移网络请求),如下所示:

JavaScript

var doesRequestAcceptHtml = function (request) { return
request.headers.get(‘Accept’) .split(‘,’) .some(function (type) { return
type === ‘text/html’; }); }; self.addEventListener(‘fetch’, function
(event) { var request = event.request; if
(doesRequestAcceptHtml(request)) { // HTML pages fallback to offline
page event.respondWith( fetch(request) .catch(function () { return
caches.match(‘/offline-page.html’); }) ); } else { // Default fetch
behaviour // Cache first for all other requests event.respondWith(
caches.match(request) .then(function (response) { return response ||
fetch(request); }) ); } });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var doesRequestAcceptHtml = function (request) {
    return request.headers.get(‘Accept’)
        .split(‘,’)
        .some(function (type) { return type === ‘text/html’; });
};
 
self.addEventListener(‘fetch’, function (event) {
    var request = event.request;
    if (doesRequestAcceptHtml(request)) {
        // HTML pages fallback to offline page
        event.respondWith(
            fetch(request)
                .catch(function () {
                    return caches.match(‘/offline-page.html’);
                })
        );
    } else {
        // Default fetch behaviour
        // Cache first for all other requests
        event.respondWith(
            caches.match(request)
                .then(function (response) {
                    return response || fetch(request);
                })
        );
    }
});

就只需求这么多!theguardian.com
上的 负有代码都是在 GitHub
上开源 的,所以您可以去这儿查看我们的
service worker
的总体版本,或者直接从生育环境上访问

俺们有充足的说辞为这个新的浏览器技术欢呼喝彩,因为它可以用来让您的网站像明日的原生应用相同,拥有完美的离线体验。将来当
theguardian.com 完全迁移到 HTTPS
之后,离线页面的主要性会明显增加,我们可以提供进一步健全的离线体验。设想一下您在上下班途中网络很差的时候访问
theguardian.com,你会看出专门为您订制的个性化内容,它们是在你此前访问网站时由浏览器缓存下来的。它在装置进程中也不会生出任何不便,你所急需的只是造访这几个网站而已,不像原生应用,还索要用户有一个利用公司的账号才能安装。瑟维斯(Service)worker
同样可以辅助我们升高网站的加载速度,因为网站的框架可以被有限支持地缓存下来,就好像原生应用相同。

要是你对 service worker
很感兴趣,想要精晓越来越多内容的话,开发者 Matt
Gaunt(Chrome的忠实支持者)写了一篇更加详实地 介绍 Service
Worker的文章。

打赏协助自己翻译越来越多好小说,谢谢!

打赏译者

瑟维斯(Service)(Service) Worker的生命周期

瑟维斯(Service) worker拥有一个全然独立于Web页面的生命周期。

要让一个service
worker在您的网站上生效,你需求先在你的网页中登记它。注册一个service
worker之后,浏览器会在后台默默启动一个service worker的设置进度。

在装置进度中,浏览器会加载并缓存一些静态资源。借使所有的文书被缓存成功,service
worker就安装成功了。如若有另曾外祖父文加载或缓存战败,那么安装进度就会战败,service
worker就不可以被激活(也即没能安装成功)。倘使暴发如此的问题,别担心,它会在下次再尝试安装。

当安装到位后,service
worker的下一步是激活,在这一阶段,你还足以升级一个service
worker的版本,具体内容大家会在背后讲到。

在激活之后,service
worker将接管所有在友好管辖域范围内的页面,可是只要一个页面是刚刚注册了service
worker,那么它这一遍不会被接管,到下五遍加载页面的时候,service
worker才会生效。

当service
worker接管了页面之后,它恐怕有二种景况:要么被甘休以节约内存,要么会处理fetch和message事件,那多个事件分别发出于一个网络请求出现依旧页面上发送了一个音讯。

下图是一个简化了的service worker初次安装的生命周期:

亚洲必赢官网 5

其次步:成立一个应用程序清单(Manifest)

应用程序清单提供了和脚下渐进式Web应用的连锁音讯,如:

  • 应用程序名
  • 描述
  • 装有图片(包蕴主显示屏图标,启动显示屏页面和用的图片或者网页上用的图片)

真相上讲,程序清单是页面上用到的图标和焦点等资源的元数据。

程序清单是一个放在您使用根目录的JSON文件。该JSON文件重回时必须抬高Content-Type: application/manifest+json 或者 Content-Type: application/jsonHTTP头音讯。程序清单的文书名不限,在本文的言传身教代码中为manifest.json

{ “name” : “PWA Website”, “short_name” : “PWA”, “description” : “An
example PWA website”, “start_url” : “/”, “display” : “standalone”,
“orientation” : “any”, “background_color” : “#ACE”, “theme_color” :
“#ACE”, “icons”: [ { “src” : “/images/logo/logo072.png”, “sizes” :
“72×72”, “type” : “image/png” }, { “src” : “/images/logo/logo152.png”,
“sizes” : “152×152”, “type” : “image/png” }, { “src” :
“/images/logo/logo192.png”, “sizes” : “192×192”, “type” : “image/png” },
{ “src” : “/images/logo/logo256.png”, “sizes” : “256×256”, “type” :
“image/png” }, { “src” : “/images/logo/logo512.png”, “sizes” :
“512×512”, “type” : “image/png” } ] }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
  "name"              : "PWA Website",
  "short_name"        : "PWA",
  "description"       : "An example PWA website",
  "start_url"         : "/",
  "display"           : "standalone",
  "orientation"       : "any",
  "background_color"  : "#ACE",
  "theme_color"       : "#ACE",
  "icons": [
    {
      "src"           : "/images/logo/logo072.png",
      "sizes"         : "72×72",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo152.png",
      "sizes"         : "152×152",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo192.png",
      "sizes"         : "192×192",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo256.png",
      "sizes"         : "256×256",
      "type"          : "image/png"
    },
    {
      "src"           : "/images/logo/logo512.png",
      "sizes"         : "512×512",
      "type"          : "image/png"
    }
  ]
}

程序清单文件建立完将来,你需要在每个页面上引用该文件:

<link rel=”manifest” href=”/manifest.json”>

1
<link rel="manifest" href="/manifest.json">

以下属性在程序清单中时时应用,介绍表达如下:

  • name: 用户看到的选用名称
  • short_name: 应用短名称。当展现应用名称的地点不够时,将应用该名称。
  • description: 使用描述。
  • start_url: 利用开端路径,相对路径,默许为/。
  • scope: URL范围。比如:若是您将“/app/”设置为URL范围时,那个应用就会向来在这几个目录中。
  • background_color: 欢迎页面的背景颜色和浏览器的背景颜色(可选)
  • theme_color: 行使的主旨颜色,一般都会和背景颜色一样。那一个设置决定了运用怎么样体现。
  • orientation: 优先旋转方向,可选的值有:any, natural, landscape,
    landscape-primary, landscape-secondary, portrait, portrait-primary,
    and portrait-secondary
  • display: 彰显形式——fullscreen(无Chrome),standalone(和原生应用相同),minimal-ui(最小的一套UI控件集)或者browser(最古老的利用浏览器标签显示)
  • icons: 一个含有所有图片的数组。该数组中每个元素包括了图片的URL,大小和连串。

message事件

页面和serviceWorker之间可以因此posetMessage()方法发送新闻,发送的新闻可以经过message事件接收到。

那是一个双向的经过,页面可以发信息给service worker,service
worker也足以发送音讯给页面,由于这么些特性,可以将service
worker作为中间纽带,使得一个域名如故子域名下的多个页面可以无限制通讯。

此处是一个小的页面之间通讯demo

打赏协助我翻译越多好小说,谢谢!

亚洲必赢官网 6

1 赞 收藏
评论

在大家初步写码此前

从这个项目地址拿到chaches
polyfill。

这个polyfill支持CacheStorate.match,Cache.add和Cache.addAll,而现在Chrome
M40实现的Cache
API还没有支持那个措施。

将dist/serviceworker-cache-polyfill.js放到你的网站中,在service
worker中通过importScripts加载进来。被service
worker加载的台本文件会被电动缓存。

JavaScript

importScripts(‘serviceworker-cache-polyfill.js’);

1
importScripts(‘serviceworker-cache-polyfill.js’);

需要HTTPS

在开发阶段,你可以经过localhost使用service
worker,不过借使上线,就要求你的server协理HTTPS。

您可以通过service
worker勒迫连接,伪造和过滤响应,极度逆天。即便你能够约束自己不干坏事,也会有人想干坏事。所以为了以防万一别人使坏,你只好在HTTPS的网页上登记service
workers,那样我们才得以防患加载service
worker的时候不被坏人篡改。(因为service
worker权限很大,所以要谨防它自己被歹徒篡改利用——译者注)

Github
Pages赶巧是HTTPS的,所以它是一个不错的原状实验田。

若果您想要让您的server扶助HTTPS,你要求为你的server获得一个TLS证书。不一致的server安装方法差别,阅读协助文档并透过Mozilla’s
SSL config
generator刺探最佳实践。

其三步:创造一个 瑟维斯(Service) Worker

Service(Service) Worker
是一个可编程的服务器代理,它可以阻止或者响应网络请求。Service(Service) Worker
是位于应用程序根目录的一个个的JavaScript文件。

你需求在页面对应的JavaScript文件中注册该瑟维斯(Service)Worker:

if (‘serviceWorker’ in navigator) { // register service worker
navigator.serviceWorker.register(‘/service-worker.js’); }

1
2
3
4
if (‘serviceWorker’ in navigator) {
  // register service worker
  navigator.serviceWorker.register(‘/service-worker.js’);
}

只要你不须要离线的有关职能,您可以只成立一个 /service-worker.js文件,那样用户就能够平素设置您的Web应用了!

瑟维斯(Service)(Service)Worker那些概念可能相比难懂,它实质上是一个行事在其余线程中的标准的Worker,它不可以访问页面上的DOM元素,没有页面上的API,不过足以阻止所有页面上的网络请求,包括页面导航,请求资源,Ajax请求。

地点就是接纳全站HTTPS的显要原因了。若是你没有在您的网站中使用HTTPS,一个第三方的台本就足以从其余的域名注入他协调的ServiceWorker,然后篡改所有的央求——那无疑是那些危急的。

Service Worker 会响应多个事件:install,activate和fetch。

应用service workder缓存文件

下边介绍一个选取service worker缓存离线文件的例子
未雨绸缪index.js,用于注册service-worker

JavaScript

if (navigator.serviceWorker) {
navigator.serviceWorker.register(‘service-worker.js’).then(function(registration)
{ console.log(‘service worker 注册成功’); }).catch(function (err) {
console.log(‘servcie worker 注册败北’) }); }

1
2
3
4
5
6
7
if (navigator.serviceWorker) {
    navigator.serviceWorker.register(‘service-worker.js’).then(function(registration) {
        console.log(‘service worker 注册成功’);
    }).catch(function (err) {
        console.log(‘servcie worker 注册失败’)
    });
}

在上述代码中,注册了service-worker.js作为当下路线下的service
worker。由于service
worker的权力很高,所有的代码都急需是安全可相信的,所以唯有https站点才方可运用service
worker,当然localhost是一个特例。
挂号停止,现在始于写service-worker.js代码。
基于前边的生命周期图,在一个新的service
worker被登记之后,首先会触发install事件,在service-workder.js中,可以经过监听install事件进展部分初阶化工作,或者怎么样也不做。
因为大家是要缓存离线文件,所以能够在install事件中开头缓存,不过只是将文件加到caches缓存中,真正想让浏览器采纳缓存文件须求在fetch事件中阻止

JavaScript

var cacheFiles = [ ‘about.js’, ‘blog.js’ ];
self.addEventListener(‘install’, function (evt) { evt.waitUntil(
caches.open(‘my-test-cahce-v1’).then(function (cache) { return
cache.addAll(cacheFiles); }) ); });

1
2
3
4
5
6
7
8
9
10
11
var cacheFiles = [
    ‘about.js’,
    ‘blog.js’
];
self.addEventListener(‘install’, function (evt) {
    evt.waitUntil(
        caches.open(‘my-test-cahce-v1’).then(function (cache) {
            return cache.addAll(cacheFiles);
        })
    );
});

率先定义了须求缓存的文本数组cacheFile,然后在install事件中,缓存那一个文件。
evt是一个Install伊夫(Eve)nt对象,继承自Extendable伊芙(Eve)nt,其中的waitUntil()方法接收一个promise对象,直到这么些promise对象成功resolve之后,才会连续运行service-worker.js。
caches是一个CacheStorage对象,使用open()方法打开一个缓存,缓存通过名称进行区分。
赢得cache实例之后,调用addAll()方法缓存文件。

那样就将文件添加到caches缓存中了,想让浏览器接纳缓存,还亟需拦截fetch事件

JavaScript

// 缓存图片 self.add伊夫(Eve)ntListener(‘fetch’, function (evt) {
evt.respondWith( caches.match(evt.request).then(function(response) { if
(response) { return response; } var request = evt.request.clone();
return fetch(request).then(function (response) { if (!response &&
response.status !== 200 &&
!response.headers.get(‘Content-type’).match(/image/)) { return response;
} var responseClone = response.clone();
caches.open(‘my-test-cache-v1’).then(function (cache) {
cache.put(evt.request, responseClone); }); return response; }); }) ) });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 缓存图片
self.addEventListener(‘fetch’, function (evt) {
    evt.respondWith(
        caches.match(evt.request).then(function(response) {
            if (response) {
                return response;
            }
            var request = evt.request.clone();
            return fetch(request).then(function (response) {
                if (!response && response.status !== 200 && !response.headers.get(‘Content-type’).match(/image/)) {
                    return response;
                }
                var responseClone = response.clone();
                caches.open(‘my-test-cache-v1’).then(function (cache) {
                    cache.put(evt.request, responseClone);
                });
                return response;
            });
        })
    )
});

通过监听fetch事件,service worker可以回来自己的响应。

率先检缓存中是还是不是曾经缓存了这些请求,若是有,就直接再次来到响应,就收缩了一次网络请求。否则由service
workder发起请求,这时的service workder起到了一个中路代理的功能。

service worker请求的经过通过fetch
api完毕,得到response对象以后进行过滤,查看是否是图片文件,若是否,就直接回到请求,不会缓存。

假即使图表,要先复制一份response,原因是request或者response对象属于stream,只可以使用四回,之后一份存入缓存,另一份发送给页面。
那就是service worker的雄强之处:拦截请求,伪造响应。fetch
api在那边也起到了很大的职能。

 

service
worker的更新很不难,只要service-worker.js的文书内容有更新,就会动用新的本子。不过有几许要专注:旧缓存文件的消除、新文件的缓存要在activate事件中开展,因为可能旧的页面还在动用此前的缓存文件,清除之后会失去效率。

 

在第一使用service worker的经过中,也赶上了一部分问题,下边是其中四个

有关小编:Erucy

亚洲必赢官网 7

已经的SharePoint喵星程序猿(暂时还挂着微软MVP的名头),现在的Azure/.Net/MongoDB/Cordova/前端程序猿,偶尔写小说
个人主页 ·
我的文章 ·
46 ·
  

亚洲必赢官网 8

使用Service Worker

当今大家有了polyfill,并且搞定了HTTPS,让我们看看到底怎么用service
worker。

Install事件

该事件将在运用设置已毕后触发。大家一般在那里运用Cache
API缓存一些必不可少的文件。

率先,我们须要提供如下配置

  1. 缓存名称(CACHE)以及版本(version)。应用可以有三个缓存存储,但是在使用时只会采取其中一个缓存存储。每当缓存存储有变动时,新的版本号将会指定到缓存存储中。新的缓存存储将会作为当前的缓存存储,从前的缓存存储将会被作废。
  2. 一个离线的页面地址(offlineURL):当用户访问了以前未曾访问过的地点时,该页面将会体现。
  3. 一个暗含了装有必须文件的数组,包蕴保持页面正常机能的CSS和JavaScript。在本示例中,我还添加了主页和logo。当有两样的URL指向同一个资源时,你也足以将那个URL分别写到这几个数组中。offlineURL将会投入到那么些数组中。
  4. 俺们也足以将一部分非须要的缓存文件(installFilesDesirable)。那么些文件在安装进度中校会被下载,但假若下载败北,不会触发安装战败。

// 配置文件 const version = ‘1.0.0’, CACHE = version + ‘::PWAsite’,
offlineURL = ‘/offline/’, installFilesEssential = [ ‘/’,
‘/manifest.json’, ‘/css/styles.css’, ‘/js/main.js’,
‘/js/offlinepage.js’, ‘/images/logo/logo152.png’ ].concat(offlineURL),
installFilesDesirable = [ ‘/favicon.ico’, ‘/images/logo/logo016.png’,
‘/images/hero/power-pv.jpg’, ‘/images/hero/power-lo.jpg’,
‘/images/hero/power-hi.jpg’ ];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 配置文件
const
  version = ‘1.0.0’,
  CACHE = version + ‘::PWAsite’,
  offlineURL = ‘/offline/’,
  installFilesEssential = [
    ‘/’,
    ‘/manifest.json’,
    ‘/css/styles.css’,
    ‘/js/main.js’,
    ‘/js/offlinepage.js’,
    ‘/images/logo/logo152.png’
  ].concat(offlineURL),
  installFilesDesirable = [
    ‘/favicon.ico’,
    ‘/images/logo/logo016.png’,
    ‘/images/hero/power-pv.jpg’,
    ‘/images/hero/power-lo.jpg’,
    ‘/images/hero/power-hi.jpg’
  ];

installStaticFiles() 方法运用基于Promise的方法使用Cache
API将文件存储到缓存中。

// 安装静态资源 function installStaticFiles() { return
caches.open(CACHE) .then(cache => { // 缓存可选文件
cache.addAll(installFilesDesirable); // 缓存必须文件 return
cache.addAll(installFilesEssential); }); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 安装静态资源
function installStaticFiles() {
  return caches.open(CACHE)
    .then(cache => {
      // 缓存可选文件
      cache.addAll(installFilesDesirable);
      // 缓存必须文件
      return cache.addAll(installFilesEssential);
    });
}

最后,大家添加一个install的风云监听器。waitUntil措施有限帮助了service
worker不会设置直到其相关的代码被实施。那里它会履行installStaticFiles()方法,然后self.skipWaiting()方法来激活service
worker:

// 应用设置 self.add伊夫ntListener(‘install’, event => {
console.log(‘service worker: install’); // 缓存首要文件 event.waitUntil(
installStaticFiles() .then(() => self.skipWaiting()) ); });

1
2
3
4
5
6
7
8
9
10
11
12
// 应用安装
self.addEventListener(‘install’, event => {
  console.log(‘service worker: install’);
  // 缓存主要文件
  event.waitUntil(
    installStaticFiles()
    .then(() => self.skipWaiting())
  );
});

题材1. 周转时刻

service
worker并不是一向在后台运行的。在页面关闭后,浏览器可以持续保持service
worker运行,也可以关闭service
worker,那有赖于与浏览器自己的一举一动。所以不要定义一些全局变量,例如下边的代码(来自):

JavaScript

var hitCounter = 0; this.addEventListener(‘fetch’, function(event) {
hitCounter++; event.respondWith( new Response(‘Hit number ‘ +
hitCounter) ); });

1
2
3
4
5
6
7
8
var hitCounter = 0;
 
this.addEventListener(‘fetch’, function(event) {
  hitCounter++;
  event.respondWith(
    new Response(‘Hit number ‘ + hitCounter)
  );
});

回来的结果或者是尚未规律的:1,2,1,2,1,1,2….,原因是hitCounter并不曾一向留存,如若浏览器关闭了它,下次起步的时候hitCounter就赋值为0了
这样的事情导致调试代码困难,当你更新一个service
worker以后,唯有在打开新页面未来才可能选取新的service
worker,在调节进度中不时等上一两分钟才会使用新的,比较抓狂。

如何注册和设置service worker

要设置service
worker,你须求在您的页面上登记它。那么些手续告诉浏览器你的service
worker脚本在哪儿。

JavaScript

if (‘serviceWorker’ in navigator) {
navigator.serviceWorker.register(‘/sw.js’).then(function(registration) {
// Registration was successful console.log(‘ServiceWorker registration
successful with scope: ‘, registration.scope); }).catch(function(err) {
// registration failed 🙁 console.log(‘ServiceWorker registration
failed: ‘, err); }); }

1
2
3
4
5
6
7
8
9
if (‘serviceWorker’ in navigator) {
  navigator.serviceWorker.register(‘/sw.js’).then(function(registration) {
    // Registration was successful
    console.log(‘ServiceWorker registration successful with scope: ‘,    registration.scope);
  }).catch(function(err) {
    // registration failed 🙁
    console.log(‘ServiceWorker registration failed: ‘, err);
  });
}

地点的代码检查service worker API是还是不是可用,如若可用,service
worker /sw.js 被注册。

如果那些service worker已经被注册过,浏览器会活动忽略下边的代码。

有一个须要特地表达的是service
worker文件的路线,你肯定留神到了在那么些事例中,service
worker文件被放在那个域的根目录下,那象征service
worker和网站同源。换句话说,这么些service
work将会接收那么些域下的富有fetch事件。如若本身将service
worker文件注册为/example/sw.js,那么,service worker只能收到/example/路径下的fetch事件(例如: /example/page1/, /example/page2/)。

今昔你可以到 chrome://inspect/#service-workers 检查service worker是否对你的网站启用了。

亚洲必赢官网 9

当service
worker第一版被已毕的时候,你也足以在chrome://serviceworker-internals中查看,它很有用,通过它可以最直观地熟悉service worker的生命周期,不过这个功能很快就会被移到chrome://inspect/#service-workers中。

您会发觉那几个效率可以很便宜地在一个效仿窗口中测试你的service
worker,那样你可以关闭和重复打开它,而不会潜移默化到您的新窗口。任何创设在模仿窗口中的注册服务和缓存在窗口被关门时都将一去不归。

Activate 事件

以此事件会在service
worker被激活时暴发。你恐怕不须求以此事件,不过在示范代码中,我们在该事件时有暴发时将老的缓存全体清理掉了:

// clear old caches function clearOldCaches() { return caches.keys()
.then(keylist => { return Promise.all( keylist .filter(key => key
!== CACHE) .map(key => caches.delete(key)) ); }); } // application
activated self.addEventListener(‘activate’, event => {
console.log(‘service worker: activate’); // delete old caches
event.waitUntil( clearOldCaches() .then(() => self.clients.claim())
); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// clear old caches
function clearOldCaches() {
  return caches.keys()
    .then(keylist => {
      return Promise.all(
        keylist
          .filter(key => key !== CACHE)
          .map(key => caches.delete(key))
      );
    });
}
// application activated
self.addEventListener(‘activate’, event => {
  console.log(‘service worker: activate’);
    // delete old caches
  event.waitUntil(
    clearOldCaches()
    .then(() => self.clients.claim())
    );
});

注意self.clients.claim()施行时将会把近日service
worker作为被激活的worker。

Fetch 事件
该事件将会在网络初阶请求时发起。该事件处理函数中,大家能够利用respondWith()艺术来胁迫HTTP的GET请求然后回到:

  1. 从缓存中取到的资源文件
  2. 假设第一步失利,资源文件将会从网络中拔取Fetch API来获取(和service
    worker中的fetch事件非亲非故)。获取到的资源将会投入到缓存中。
  3. 比方第一步和第二步均未果,将会从缓存中回到正确的资源文件。

// application fetch network data self.addEventListener(‘fetch’, event
=> { // abandon non-GET requests if (event.request.method !== ‘GET’)
return; let url = event.request.url; event.respondWith(
caches.open(CACHE) .then(cache => { return cache.match(event.request)
.then(response => { if (response) { // return cached file
console.log(‘cache fetch: ‘ + url); return response; } // make network
request return fetch(event.request) .then(newreq => {
console.log(‘network fetch: ‘ + url); if (newreq.ok)
cache.put(event.request, newreq.clone()); return newreq; }) // app is
offline .catch(() => offlineAsset(url)); }); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// application fetch network data
self.addEventListener(‘fetch’, event => {
  // abandon non-GET requests
  if (event.request.method !== ‘GET’) return;
  let url = event.request.url;
  event.respondWith(
    caches.open(CACHE)
      .then(cache => {
        return cache.match(event.request)
          .then(response => {
            if (response) {
              // return cached file
              console.log(‘cache fetch: ‘ + url);
              return response;
            }
            // make network request
            return fetch(event.request)
              .then(newreq => {
                console.log(‘network fetch: ‘ + url);
                if (newreq.ok) cache.put(event.request, newreq.clone());
                return newreq;
              })
              // app is offline
              .catch(() => offlineAsset(url));
          });
      })
  );
});

offlineAsset(url)主意中运用了部分helper方法来回到正确的数量:

// 是否为图片地址? let iExt = [‘png’, ‘jpg’, ‘jpeg’, ‘gif’, ‘webp’,
‘bmp’].map(f => ‘.’ + f); function isImage(url) { return
iExt.reduce((ret, ext) => ret || url.endsWith(ext), false); } //
return 重回离线资源 function offlineAsset(url) { if (isImage(url)) { //
再次回到图片 return new Response( ‘<svg role=”img” viewBox=”0 0 400 300″
xmlns=”
d=”M0 0h400v300H0z” fill=”#eee” /><text x=”200″ y=”150″
text-anchor=”middle” dominant-baseline=”middle” font-family=”sans-serif”
font-size=”50″ fill=”#ccc”>offline</text></svg>’, {
headers: { ‘Content-Type’: ‘image/svg+xml’, ‘Cache-Control’: ‘no-store’
}} ); } else { // return page return caches.match(offlineURL); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 是否为图片地址?
let iExt = [‘png’, ‘jpg’, ‘jpeg’, ‘gif’, ‘webp’, ‘bmp’].map(f => ‘.’ + f);
function isImage(url) {
  
  return iExt.reduce((ret, ext) => ret || url.endsWith(ext), false);
  
}
  
  
// return 返回离线资源
function offlineAsset(url) {
  
  if (isImage(url)) {
  
    // 返回图片
    return new Response(
      ‘<svg role="img" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg"><title>offline</title><path d="M0 0h400v300H0z" fill="#eee" /><text x="200" y="150" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="50" fill="#ccc">offline</text></svg>’,
      { headers: {
        ‘Content-Type’: ‘image/svg+xml’,
        ‘Cache-Control’: ‘no-store’
      }}
    );
  
  }
  else {
  
    // return page
    return caches.match(offlineURL);
  
  }
  
}

offlineAsset()方法检查请求是或不是为一个图片,然后回来一个含有“offline”文字的SVG文件。其余请求将会回到
offlineURL 页面。

Chrome开发者工具中的瑟维斯(Service)Worker部分提供了有关当前页面worker的新闻。其中会显得worker中发出的失实,还足以强制刷新,也得以让浏览器进入离线方式。

Cache Storage
部分例举了现阶段享有曾经缓存的资源。你可以在缓存须求立异的时候点击refresh按钮。

题材2. 权力太大

当service worker监听fetch事件未来,对应的呼吁都会透过service
worker。通过chrome的network工具,可以见见此类请求会标注:from service
worker。若是service
worker中冒出了问题,会促成所有请求失利,包括一般的html文件。所以service
worker的代码质地、容错性一定要很好才能有限援助web app正常运转。

 

参照文章:

1. 

2. 

3. 

4. 

5. 

1 赞 3 收藏
评论

亚洲必赢官网 10

瑟维斯 Worker的设置步骤

在页面上形成注册手续之后,让咱们把注意力转到service
worker的脚本里来,在那中间,大家要成功它的装置步骤。

在最主旨的例证中,你要求为install事件定义一个callback,并决定怎样文件你想要缓存。

JavaScript

// The files we want to cache var urlsToCache = [ ‘/’,
‘/styles/main.css’, ‘/script/main.js’ ]; // Set the callback for the
install step self.addEventListener(‘install’, function(event) { //
Perform install steps });

1
2
3
4
5
6
7
8
9
10
11
// The files we want to cache
var urlsToCache = [
  ‘/’,
  ‘/styles/main.css’,
  ‘/script/main.js’
];
 
// Set the callback for the install step
self.addEventListener(‘install’, function(event) {
    // Perform install steps
});

在我们的install callback中,大家需求进行以下步骤:

  1. 翻开一个缓存
  2. 缓存大家的文书
  3. 操纵是还是不是享有的资源是或不是要被缓存

JavaScript

var CACHE_NAME = ‘my-site-cache-v1’; var urlsToCache = [ ‘/’,
‘/styles/main.css’, ‘/script/main.js’ ];
self.addEventListener(‘install’, function(event) { // Perform install
steps event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) {
console.log(‘Opened cache’); return cache.addAll(urlsToCache); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var CACHE_NAME = ‘my-site-cache-v1’;
var urlsToCache = [
  ‘/’,
  ‘/styles/main.css’,
  ‘/script/main.js’
];
 
self.addEventListener(‘install’, function(event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log(‘Opened cache’);
        return cache.addAll(urlsToCache);
      })
  );
});

下面的代码中,大家经过caches.open打开大家指定的cache文件名,然后我们调用cache.addAll并传播咱们的公文数组。那是由此一连串promise(caches.open

cache.addAll)已毕的。event.waitUntil得到一个promise并行使它来收获安装费用的年华以及是还是不是安装成功。

要是具有的文本都被缓存成功了,那么service
worker就设置成功了。要是其余一个文本下载铩羽,那么安装步骤就会破产。那个办法允许你依靠于您自己指定的拥有资源,不过那象征你要求非凡小心谨慎地控制怎样文件必要在设置步骤中被缓存。指定了太多的公文的话,就会增多设置失利率。

上面只是一个简约的事例,你可以在install事件中履行此外操作依旧甚至忽视install事件。

第四步:成立可用的离线页面

离线页面能够是静态的HTML,一般用来提醒用户眼前恳请的页面暂时无法使用。但是,大家得以提供一些得以阅读的页面链接。

Cache
API能够在main.js中使用。可是,该API使用Promise,在不支持Promise的浏览器中会战败,所有的JavaScript执行会由此受到震慑。为了防止那种状态,在做客/js/offlinepage.js的时候大家添加了一段代码来检查当前是还是不是在离线环境中:

/js/offlinepage.js 中以版本号为名称保存了多年来的缓存,获取具有URL,删除不是页面的URL,将这么些URL排序然后将装有缓存的URL显示在页面上:

// cache name const CACHE = ‘::PWAsite’, offlineURL = ‘/offline/’, list
= document.getElementById(‘cachedpagelist’); // fetch all caches
window.caches.keys() .then(cacheList => { // find caches by and order
by most recent cacheList = cacheList .filter(cName =>
cName.includes(CACHE)) .sort((a, b) => a – b); // open first cache
caches.open(cacheList[0]) .then(cache => { // fetch cached pages
cache.keys() .then(reqList => { let frag =
document.createDocumentFragment(); reqList .map(req => req.url)
.filter(req => (req.endsWith(‘/’) || req.endsWith(‘.html’)) &&
!req.endsWith(offlineURL)) .sort() .forEach(req => { let li =
document.createElement(‘li’), a =
li.appendChild(document.createElement(‘a’)); a.setAttribute(‘href’,
req); a.textContent = a.pathname; frag.appendChild(li); }); if (list)
list.appendChild(frag); }); }) });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// cache name
const
  CACHE = ‘::PWAsite’,
  offlineURL = ‘/offline/’,
  list = document.getElementById(‘cachedpagelist’);
// fetch all caches
window.caches.keys()
  .then(cacheList => {
    // find caches by and order by most recent
    cacheList = cacheList
      .filter(cName => cName.includes(CACHE))
      .sort((a, b) => a – b);
    // open first cache
    caches.open(cacheList[0])
      .then(cache => {
        // fetch cached pages
        cache.keys()
          .then(reqList => {
            let frag = document.createDocumentFragment();
            reqList
              .map(req => req.url)
              .filter(req => (req.endsWith(‘/’) || req.endsWith(‘.html’)) && !req.endsWith(offlineURL))
              .sort()
              .forEach(req => {
                let
                  li = document.createElement(‘li’),
                  a = li.appendChild(document.createElement(‘a’));
                  a.setAttribute(‘href’, req);
                  a.textContent = a.pathname;
                  frag.appendChild(li);
              });
            if (list) list.appendChild(frag);
          });
      })
  });

什么缓存和重临Request

你早就设置了service worker,你现在可以再次来到您缓存的请求了。

当service
worker被安装成功还要用户浏览了另一个页面或者刷新了现阶段的页面,service
worker将初叶收取到fetch事件。上面是一个例子:

JavaScript

self.addEventListener(‘fetch’, function(event) { event.respondWith(
caches.match(event.request) .then(function(response) { // Cache hit –
return response if (response) { return response; } return
fetch(event.request); } ) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
self.addEventListener(‘fetch’, function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit – return response
        if (response) {
          return response;
        }
 
        return fetch(event.request);
      }
    )
  );
});

地点的代码里大家定义了fetch事件,在event.respondWith里,大家传入了一个由caches.match发生的promise.caches.match
查找request中被service worker缓存命中的response。

万一大家有一个命中的response,大家回去被缓存的值,否则大家回到一个实时从网络请求fetch的结果。那是一个非凡不难的例证,使用具有在install步骤下被缓存的资源。

即使大家想要增量地缓存新的伸手,我们得以因此处理fetch请求的response并且拉长它们到缓存中来兑现,例如:

JavaScript

self.addEventListener(‘fetch’, function(event) { event.respondWith(
caches.match(event.request) .then(function(response) { // Cache hit –
return response if (response) { return response; } // IMPORTANT: Clone
the request. A request is a stream and // can only be consumed once.
Since we are consuming this // once by cache and once by the browser for
fetch, we need // to clone the response var fetchRequest =
event.request.clone(); return fetch(fetchRequest).then(
function(response) { // Check if we received a valid response
if(!response || response.status 亚洲必赢官网,!== 200 || response.type !== ‘basic’) {
return response; } // IMPORTANT: Clone the response. A response is a
stream // and because we want the browser to consume the response // as
well as the cache consuming the response, we need // to clone it so we
have 2 stream. var responseToCache = response.clone();
caches.open(CACHE_NAME) .then(function(cache) {
cache.put(event.request, responseToCache); }); return response; } ); })
); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
self.addEventListener(‘fetch’, function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit – return response
        if (response) {
          return response;
        }
 
        // IMPORTANT: Clone the request. A request is a stream and
        // can only be consumed once. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response
        var fetchRequest = event.request.clone();
 
        return fetch(fetchRequest).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== ‘basic’) {
              return response;
            }
 
            // IMPORTANT: Clone the response. A response is a stream
            // and because we want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have 2 stream.
            var responseToCache = response.clone();
 
            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });
 
            return response;
          }
        );
      })
    );
});

代码里大家所做工作包括:

  1. 累加一个callback到fetch请求的 .then 方法中
  2. 只要我们获取了一个response,大家开展如下的自我批评:
    1. 担保response是卓有功用的
    2. 反省response的场所是或不是是200
    3. 有限支撑response的品类是basic,这象征请求我是同源的,非同源(即跨域)的伸手也不可以被缓存。
  3. 若果大家透过了自我批评,clone以此请求。这么做的原委是如若response是一个Stream,那么它的body只好被读取两次,所以我们得将它克隆出来,一份发给浏览器,一份发给缓存。

开发者工具

Chrome浏览器提供了一层层的工具来救助你来调节ServiceWorker,日志也会直接突显在控制台上。

你最好应用匿名模式来举行开发工作,那样可以排除缓存对开发的苦恼。

最后,Chrome的Lighthouse伸张也得以为你的渐进式Web应用提供一些改善音讯。

如何翻新一个瑟维斯(Service)(Service) Worker

您的service
worker总有亟待创新的那一天。当那一天来到的时候,你须求按照如下步骤来更新:

  1. 立异您的service worker的JavaScript文件
    1. 当用户浏览你的网站,浏览器尝试在后台下载service
      worker的本子文件。只要服务器上的文件和本地文件有一个字节分歧,它们就被判定为急需更新。
  2. 履新后的service worker将起来运转,install event被再度触发。
  3. 在那一个日子节点上,当前页面生效的照样是老版本的service
    worker,新的servicer worker将进入”waiting”状态。
  4. 眼前页面被关闭之后,老的service worker进度被杀掉,新的servicer
    worker正式生效。
  5. 假如新的service worker生效,它的activate事件被触发。

代码更新后,寻常要求在activate的callback中实施一个管理cache的操作。因为你会须求破除掉之前旧的数量。我们在activate而不是install的时候实施这么些操作是因为只要大家在install的时候立刻执行它,那么如故在运转的旧版本的多少就坏了。

事先大家只利用了一个缓存,叫做my-site-cache-v1,其实我们也可以使用多个缓存的,例如一个给页面使用,一个给blog的内容提交使用。这意味着,在install步骤里,我们可以创建两个缓存,pages-cache-v1和blog-posts-cache-v1,在activite步骤里,我们可以删除旧的my-site-cache-v1。

上边的代码能够循环所有的缓存,删除掉所有不在白名单中的缓存。

JavaScript

self.addEventListener(‘activate’, function(event) { var cacheWhitelist =
[‘pages-cache-v1’, ‘blog-posts-cache-v1’]; event.waitUntil(
caches.keys().then(function(cacheNames) { return Promise.all(
cacheNames.map(function(cacheName) { if
(cacheWhitelist.indexOf(cacheName) === -1) { return
caches.delete(cacheName); } }) ); }) ); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
self.addEventListener(‘activate’, function(event) {
 
  var cacheWhitelist = [‘pages-cache-v1’, ‘blog-posts-cache-v1’];
 
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

渐进式Web应用的中心绪想

渐进式Web应用是一种新的技能,所以利用的时候肯定要小心。也就是说,渐进式Web应用能够让您的网站在几个钟头内取得改进,并且在不协理渐进式Web应用的浏览器上也不会影响网站的来得。

不过我们须要考虑以下几点:

拍卖边界和填坑

这一节内容比较新,有诸多待定细节。希望这一节很快就不需求讲了(因为标准会处理那几个问题——译者注),可是现在,那个情节依旧应该被提一下。

URL隐藏

当你的行使就是一个单URL的应用程序时(比如游戏),我提出你隐藏地址栏。除此之外的图景我并不提议你隐藏地址栏。在Manifest中,display: minimal-ui 或者 display: browser对此半数以上情景的话丰盛用了。

若是设置退步了,没有很优雅的方式得到通报

如果一个worker被登记了,但是从未出现在chrome://inspect/#service-workers或chrome://serviceworker-internals,那么很可能因为异常而安装失败了,或者是产生了一个被拒绝的的promise给event.waitUtil。

要缓解那类问题,首先到 chrome://serviceworker-internals检查。打开开发者工具窗口准备调试,然后在你的install event代码中添加debugger;语句。这样,通过断点调试你更容易找到问题。

缓存过大

你无法将您网站中的所有内容缓存下来。对于小片段的网站以来缓存所有情节并不是一个题材,可是假若一个网站包含了上千个页面吗?很扎眼不是所有人对网站中的所有情节都感兴趣。存储是有限量的,假如你将装有访问过的页面都缓存下来的话,缓存大小会增加额很快。

你可以这么制定你的缓存策略:

  • 只缓存紧要的页面,比如主页,联系人页面和不久前浏览文章的页面。
  • 绝不缓存任何图片,录像和大文件
  • 定时清理旧的缓存
  • 提供一个“离线阅读”按钮,那样用户就可以挑选须要缓存哪些内容了。

fetch()近来仅扶助Service Workers

fetch霎时支持在页面上选取了,可是当前的Chrome已毕,它还只辅助service
worker。cache
API也将要在页面上被支持,可是近年来甘休,cache也还只好在service
worker中用。

缓存刷新

以身作则代码中在倡导呼吁往日会先查询缓存。当用户处于离线状态时,那很好,不过即使用户处于在线状态,那她只会浏览到相比较老旧的页面。

各个资源比如图片和视频不会转移,所以一般都把那些静态资源设置为长远缓存。那几个资源得以平昔缓存一年(31,536,000秒)。在HTTP
Header中,就是:

Cache-Control: max-age=31536000

1
Cache-Control: max-age=31536000

页面,CSS和本子文件或者变化的更频仍一些,所以您可以安装一个相比小的缓存超时时间(24钟头),并保险在用户网络连接复苏时再也从服务器请求:

Cache-Control: must-revalidate, max-age=86400

1
Cache-Control: must-revalidate, max-age=86400

您也能够在历次网站颁布时,通过更名的不二法门强制浏览重视新请求资源。

fetch()的默许参数

当您选取fetch,缺省地,请求不会带上cookies等证据,要想带上的话,需求:

JavaScript

fetch(url, { credentials: ‘include’ })

1
2
3
fetch(url, {
  credentials: ‘include’
})

那样设计是有理由的,它比XHR的在同源下默许发送凭据,但跨域时舍弃凭据的规则要来得好。fetch的一举一动更像任何的CORS请求,例如<img crossorigin>,它默认不发送cookies,除非你指定了<img crossorigin="use-credentials">.。

小结

迄今甘休,相信您要是按照本文一步一步操作下来,你也足以高速把团结的Web应用转为PWA。在转为了PWA后,假若有使用满意PWA
模型的前端控件的须求,你可以尝试纯前端表格控件SpreadJS,适用于
.NET、Java 和移动端等楼台的报表控件一定不会令你失望的。

初稿链接:

1 赞 1 收藏
评论

亚洲必赢官网 11

Non-CORS默许不扶助

默许情状下,从第三方URL跨域获得一个资源将会破产,除非对方接济了CORS。你可以拉长一个non-CORS选项到Request去防止战败。代价是那样做会再次来到一个“不透明”的response,意味着你不可能得知这几个请求究竟是水到渠成了依然败诉了。

JavaScript

cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) { return new
Request(urlToPrefetch, { mode: ‘no-cors’ }); })).then(function() {
console.log(‘All resources have been fetched and cached.’); });

1
2
3
4
5
cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) {
  return new Request(urlToPrefetch, { mode: ‘no-cors’ });
})).then(function() {
  console.log(‘All resources have been fetched and cached.’);
});

fetch()不坚守30x重定向规范

不幸,重定向在fetch()中不会被触发,那是现阶段版本的bug;

处理响应式图片

img的srcset属性或者<picture>标签会根据情况从浏览器或者网络上选择最合适尺寸的图片。

在service worker中,你想要在install步骤缓存一个图片,你有以下两种拔取:

  1. 设置具有的<picture>元素或者将被请求的srcset属性。
  2. 安装单一的low-res版本图片
  3. 设置单一的high-res版本图片

相比好的方案是2或3,因为若是把具备的图片都给下载下来存着有点浪费内存。

借使你将low-res版本在install的时候缓存了,然后在页面加载的时候你想要尝试从网络上下载high-res的版本,不过一旦high-res版本下载失利以来,就依旧用low-res版本。这一个想法很好也值得去做,然而有一个题目:

若果大家有上边三种图片:

Screen Density Width Height
1x 400 400
2x 800 800

HTML代码如下:

JavaScript

<img src=”image-src.png” srcset=”image-src.png 1x, image-2x.png 2x”
/>

1
<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" />

假若大家在一个2x的彰显格局下,浏览器会下载image-2x.png,假如大家离线,你可以读取从前缓存并回到image-src.png替代,假设从前它已经被缓存过。固然如此,由于明日的情势是2x,浏览器会把400X400的图纸突显成200X200,要防止这几个题目就要在图纸的体制上安装宽高。

JavaScript

<img src=”image-src.png” srcset=”image-src.png 1x, image-2x.png 2x”
style=”width:400px; height: 400px;” />

1
2
<img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x"
style="width:400px; height: 400px;" />

亚洲必赢官网 12

<picture>标签情况更复杂一些,难度取决于你是如何创建和使用的,但是可以通过与srcset类似的思路去解决。

改变URL Hash的Bug

在M40版本中留存一个bug,它会让页面在转移hash的时候造成service
worker为止工作。

你能够在这里找到越多相关的新闻: 

越来越多内容

那里有部分唇揭齿寒的文档可以参考:

获取救助

假使你相逢麻烦,请在Stackoverflow上发帖询问,使用‘service-worker’标签,以便于大家立刻跟进和不择手段扶助你解决问题。

赞 2 收藏
评论

亚洲必赢官网 13

网站地图xml地图