英帝国卫报的个性离线页面是这么做的,入门教程

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.  … …

本文以资源缓存为例,说美赞臣(Meadjohnson)(Karicare)(Aptamil)下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应用普通所不负有的富离线体验,定时的敦默寡言更新,音讯通告推送等作用。而新的Serviceworkers标准让在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有些局限性,例如它可以很简单地化解单页应用的题目,不过在多页应用上会很劳苦,而瑟维斯(Service)(Service)workers的面世正是为了缓解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) 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) 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,你见面到专门为您订制的个性化内容,它们是在你前边访问网站时由浏览器缓存下来的。它在安装进度中也不会时有爆发其余困苦,你所必要的只是造访这么些网站而已,不像原生应用,还亟需用户有一个用到商店的账号才能设置。Serviceworker
同样可以协理大家提高网站的加载速度,因为网站的框架可以被有限支撑地缓存下来,就像是原生应用相同。

假设你对 service worker
很感兴趣,想要明白越来越多内容的话,开发者 Matt
Gaunt(Chrome的忠实帮衬者)写了一篇越发详细地 介绍 Service
Worker的文章。

打赏支持我翻译越来越多好作品,谢谢!

打赏译者

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

Service(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)(Service) Worker

Service(Service) Worker
是一个可编程的服务器代理,它可以阻挡或者响应网络请求。瑟维斯(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,一个第三方的脚本就可以从其它的域名注入他自己的Service(Service)Worker,然后篡改所有的请求——这如实是非凡危急的。

瑟维斯(Service)(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伊芙nt对象,继承自Extendable伊芙(Eve)nt,其中的waitUntil()方法接收一个promise对象,直到这几个promise对象成功resolve之后,才会一而再运行service-worker.js。
caches是一个CacheStorage对象,使用open()方法打开一个缓存,缓存通过名称举办区分。
获取cache实例之后,调用addAll()方法缓存文件。

这么就将文件添加到caches缓存中了,想让浏览器采纳缓存,还须求拦截fetch事件

JavaScript

// 缓存图片 self.add伊芙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伊芙(Eve)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开发者工具中的ServiceWorker部分提供了有关当前页面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

Service(Service) 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 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)(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地图