blob: f8d6c966a9f1ca7fa3baac996244299f1d5c5fe6 (
plain)
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
|
---
title: Service Worker API
slug: Web/API/Service_Worker_API
tags:
- API
- Offline
- SAP
- Service Worker
- WPA
- Workers
translation_of: Web/API/Service_Worker_API
---
<p>{{ServiceWorkerSidebar}}</p>
<p class="summary">Service workers 本质上充当 Web 应用程序、浏览器与网络(可用时)之间的代理服务器。这个 API 旨在创建有效的离线体验,它会拦截网络请求并根据网络是否可用来采取适当的动作、更新来自服务器的的资源。它还提供入口以推送通知和访问后台同步 API。</p>
<h2 id="Service_worker_的概念和用法">Service worker 的概念和用法</h2>
<p>Service worker是一个注册在指定源和路径下的事件驱动<a href="/zh-CN/docs/Web/API/Worker">worker</a>。它采用JavaScript控制关联的页面或者网站,拦截并修改访问和资源请求,细粒度地缓存资源。你可以完全控制应用在特定情形(最常见的情形是网络不可用)下的表现。</p>
<p>Service worker运行在worker上下文,因此它不能访问DOM。相对于驱动应用的主JavaScript线程,它运行在其他线程中,所以不会造成阻塞。它设计为完全异步,同步API(如<a href="/zh-CN/docs/Web/API/XMLHttpRequest">XHR</a>和<a href="/zh-CN/docs/Web/Guide/API/DOM/Storage">localStorage</a>)不能在service worker中使用。</p>
<p>出于安全考量,Service workers只能由HTTPS承载,毕竟修改网络请求的能力暴露给中间人攻击会非常危险。在Firefox浏览器的<a href="https://support.mozilla.org/zh-CN/kb/%E9%9A%90%E7%A7%81%E6%B5%8F%E8%A7%88">用户隐私模式</a>,Service Worker不可用。</p>
<div class="note">
<p><strong>注意:</strong>Service workers之所以优于以前同类尝试(如<a href="http://alistapart.com/article/application-cache-is-a-douchebag">AppCache</a>),是因为它们无法支持当操作出错时终止操作。Service workers可以更细致地控制每一件事情。</p>
</div>
<div class="note">
<p><strong>注意:</strong>Service workers大量使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a>,因为通常它们会等待响应后继续,并根据响应返回一个成功或者失败的操作。Promise非常适合这种场景。</p>
</div>
<h3 id="注册">注册</h3>
<p>使用 {{domxref("ServiceWorkerContainer.register()")}} 方法首次注册service worker。如果注册成功,service worker就会被下载到客户端并尝试安装或激活(见下文),这将作用于整个域内用户可访问的URL,或者其特定子集。</p>
<h3 id="下载、安装和激活">下载、安装和激活</h3>
<p>此时,你的服务工作者(service worker)将遵守以下生命周期:</p>
<ol>
<li>下载</li>
<li>安装</li>
<li>激活</li>
</ol>
<p>用户首次访问service worker控制的网站或页面时,service worker会立刻被下载。</p>
<p>之后,在以下情况将会触发更新:</p>
<ul>
<li>一个前往作用域内页面的导航</li>
<li>在 service worker 上的一个事件被触发并且过去 24 小时没有被下载</li>
</ul>
<p>无论它与现有service worker不同(字节对比),还是第一次在页面或网站遇到service worker,如果下载的文件是新的,安装就会尝试进行。</p>
<p>如果这是首次启用service worker,页面会首先尝试安装,安装成功后它会被激活。</p>
<p>如果现有service worker已启用,新版本会在后台安装,但不会被激活,这个时序称为worker in waiting。直到所有已加载的页面不再使用旧的service worker才会激活新的service worker。只要页面不再依赖旧的service worker,新的service worker会被激活(成为active worker)。</p>
<p>你可以监听{{domxref("InstallEvent")}},事件触发时的标准行为是准备service worker用于使用,例如使用内建的storage API来创建缓存,并且放置应用离线时所需资源。</p>
<p>还有一个activate事件,触发时可以清理旧缓存和旧的service worker关联的东西。</p>
<p>Servcie worker可以通过 {{domxref("FetchEvent")}} 事件去响应请求。通过使用 {{domxref("FetchEvent.respondWith") }} 方法,你可以任意修改对于这些请求的响应。</p>
<div class="note">
<p><strong>注意</strong>: 因为<code>oninstall</code>和<code>onactivate</code>完成前需要一些时间,service worker标准提供一个<code>waitUntil</code>方法,当<code>oninstall</code>或者<code>onactivate</code>触发时被调用,接受一个promise。在这个 promise被成功resolve以前,功能性事件不会分发到service worker。</p>
</div>
<p>构建一个基本用例的完整教程,请阅读 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API/Using_Service_Workers">使用 Service Workers</a>。</p>
<h2 id="其他使用场景">其他使用场景</h2>
<p>Service workers也可以用来做这些事情:</p>
<ul>
<li>后台数据同步</li>
<li>响应来自其它源的资源请求</li>
<li>集中接收计算成本高的数据更新,比如地理位置和陀螺仪信息,这样多个页面就可以利用同一组数据</li>
<li>在客户端进行CoffeeScript,LESS,CJS/AMD等模块编译和依赖管理(用于开发目的)</li>
<li>后台服务钩子</li>
<li>自定义模板用于特定URL模式</li>
<li>性能增强,比如预取用户可能需要的资源,比如相册中的后面数张图片</li>
</ul>
<p>未来service workers能够用来做更多使web平台接近原生应用的事。 值得关注的是,其他标准也能并且将会使用service worker,例如:</p>
<ul>
<li><a href="https://github.com/slightlyoff/BackgroundSync">后台同步</a>:启动一个service worker即使没有用户访问特定站点,也可以更新缓存</li>
<li><a href="/zh-CN/docs/Web/API/Push_API">响应推送</a>:启动一个service worker向用户发送一条信息通知新的内容可用</li>
<li>对时间或日期作出响应</li>
<li>进入地理围栏</li>
</ul>
<h2 id="接口">接口</h2>
<dl>
<dt>{{domxref("Cache") }} {{Experimental_Inline}}</dt>
<dd>表示用于{{domxref("Request")}}/{{domxref("Response")}}对象对的存储,作为{{domxref("ServiceWorker")}}生命周期的一部分被缓存。</dd>
<dt>{{domxref("CacheStorage") }} {{Experimental_Inline}}</dt>
<dd>表示{{domxref("Cache")}}对象的存储。提供一个所有命名缓存的主目录,{{domxref("ServiceWorker")}}可以访问并维护名字字符串到{{domxref("Cache")}}对象的映射。</dd>
<dt>{{domxref("Client") }} {{Experimental_Inline}}</dt>
<dd>表示service worker client的作用域。一个service worker client可以是浏览器上下文的一个文档,也可以是一个由活动worker控制的{{domxref("SharedWorker")}}。</dd>
<dt>{{domxref("Clients") }} {{Experimental_Inline}}</dt>
<dd>表示一个{{domxref("Client")}}对象容器,是访问当前源的活动service worker clients的主要途径。</dd>
<dt>{{domxref("ExtendableEvent") }} {{Experimental_Inline}}</dt>
<dd>扩展被分发到{{domxref("ServiceWorkerGlobalScope")}}的<code>install和activate</code>事件时序,作为service worker生命周期的一部分。这会确保任何功能型事件(如{{domxref("FetchEvent")}})不被分发到{{domxref("ServiceWorker")}},直到它更新了数据库架构、删除过期缓存项等等以后。</dd>
<dt>{{DOMxRef("ExtendableMessageEvent")}} {{Experimental_Inline}}</dt>
<dd>The event object of a {{event("message_(ServiceWorker)","message")}} event fired on a service worker (when a channel message is received on the {{DOMxRef("ServiceWorkerGlobalScope")}} from another context) — extends the lifetime of such events.</dd>
<dt>{{domxref("FetchEvent") }}{{Experimental_Inline}}</dt>
<dd>传递给{{domxref("ServiceWorkerGlobalScope.onfetch")}}处理函数的参数,FetchEvent代表一个在{{domxref("ServiceWorker")}}的{{domxref("ServiceWorkerGlobalScope")}}中分发的请求动作。它包含关于请求和响应的结果信息,并且提供{{domxref("FetchEvent.respondWith", "FetchEvent.respondWith()")}}方法,这个方法允许我们提供任意的响应返回到控制页面。</dd>
<dt>{{domxref("InstallEvent") }}{{Experimental_Inline}}</dt>
<dd>传递给{{domxref("ServiceWorkerGlobalScope.oninstall", "oninstall")}}处理函数的参数,<code>InstallEvent接口代表一个在</code>{{domxref("ServiceWorker")}}的{{domxref("ServiceWorkerGlobalScope")}}中分发的<code>安装动作,作为</code>{{domxref("ExtendableEvent")}}的子事件,它保证诸如{{domxref("FetchEvent")}} 的功能性事件在安装过程中不会被分发。</dd>
<dt>{{DOMxRef("NavigationPreloadManager")}} {{Experimental_Inline}}</dt>
<dd>Provides methods for managing the preloading of resources with a service worker.</dd>
<dt>{{domxref("Navigator.serviceWorker") }}</dt>
<dd>返回一个{{domxref("ServiceWorkerContainer")}}对象,可以提供入口用于注册,删除,更新以及与在<a href="https://html.spec.whatwg.org/multipage/browsers.html#concept-document-window">相关 document</a>中{{domxref("ServiceWorker")}}通信的对象。</dd>
<dt>{{domxref("NotificationEvent") }} {{Experimental_Inline}}</dt>
<dd>传递给{{domxref("ServiceWorkerGlobalScope.onnotificationclick", "onnotificationclick")}}处理函数的参数,<code>NotificationEvent</code> 接口代表在{{domxref("ServiceWorker")}}里{{domxref("ServiceWorkerGlobalScope")}}中分发的单击事件通知。</dd>
</dl>
<dl>
<dt>{{domxref("ServiceWorker") }} {{Experimental_Inline}}</dt>
<dd>表示一个service worker。多个浏览的上下文(例如pages,workers等等)都能通过相同的<code>ServiceWorker对象相关联。</code></dd>
<dt>{{domxref("ServiceWorkerContainer") }} {{Experimental_Inline}}</dt>
<dd>提供一个在网络生态中把service worker 作为一个整体的对象,包括辅助注册,反注册以及更新服务工作者,并且访问service worker 的状态以及他们的注册信息。</dd>
<dt>{{domxref("ServiceWorkerGlobalScope") }}</dt>
<dd>表示service worker的全局执行上下文。</dd>
<dt>{{domxref("ServiceWorkerMessageEvent")}}{{Deprecated_Inline}}</dt>
<dd>包含关于一个发送给以<code>navigator.serviceWorker</code>为目标的事件信息。<strong>Note that this interface is deprecated in modern browsers. Service worker messages will now use the {{DOMxRef("MessageEvent")}} interface, for consistency with other web messaging features.</strong></dd>
<dt>{{domxref("ServiceWorkerRegistration") }}</dt>
<dd>表示service worker的注册。</dd>
<dt>{{DOMxRef("ServiceWorkerState")}} {{Experimental_Inline}}</dt>
<dd>Associated with its <a href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker" title="The ServiceWorker interface of the ServiceWorker API provides a reference to a service worker. Multiple browsing contexts (e.g. pages, workers, etc.) can be associated with the same service worker, each through a unique ServiceWorker object."><code>ServiceWorker</code></a>'s state.</dd>
<dt>{{domxref("SyncEvent")}} {{non-standard_inline}}</dt>
<dd>传递给同步函数的参数,SyncEvent接口代表在ServiceWorker里{{domxref("ServiceWorkerGlobalScope")}}分发的同步动作。</dd>
<dt>{{domxref("SyncManager")}} {{non-standard_inline}}</dt>
<dd>提供一个接口用于注册和返回{{domxref("SyncRegistration")}}对象。</dd>
<dt>{{domxref("WindowClient") }}{{Experimental_Inline}}</dt>
<dd>表示在浏览器上下文中记录的service worker客户端的作用域,被活动的工作者控制。是{{domxref("Client")}}对象的特殊类型,包含一些附加的方法和可用的属性。</dd>
</dl>
<h2 id="规范">规范</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('Service Workers')}}</td>
<td>{{Spec2('Service Workers')}}</td>
<td>Initial definition.</td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容性">浏览器兼容性</h2>
<p>{{ CompatibilityTable() }}</p>
<div id="compat-desktop">
<table class="compat-table">
<tbody>
<tr>
<th>Feature</th>
<th>Chrome</th>
<th>Firefox (Gecko)</th>
<th>Internet Explorer</th>
<th>Opera</th>
<th>Safari (WebKit)</th>
</tr>
<tr>
<td>Basic support</td>
<td>{{CompatChrome(40.0)}}</td>
<td>{{ CompatGeckoDesktop("44.0") }}<sup>[1]</sup></td>
<td>{{ CompatNo() }}</td>
<td>24</td>
<td>{{ CompatNo() }}</td>
</tr>
<tr>
<td>install/activate events</td>
<td>{{ CompatChrome(40.0) }}</td>
<td>{{ CompatGeckoDesktop("44.0") }}<sup>[1]</sup></td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatVersionUnknown() }}</td>
<td>{{ CompatNo() }}</td>
</tr>
<tr>
<td>fetch event/request/<br>
<code>respondWith()</code></td>
<td>{{CompatChrome(40.0)}}</td>
<td>{{ CompatGeckoDesktop("44.0") }}<sup>[1]</sup></td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
</tr>
<tr>
<td>caches/cache</td>
<td>
<p class="p1">{{CompatChrome(42.0)}}</p>
</td>
<td>{{ CompatGeckoDesktop("39.0") }}<sup>[1]</sup></td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
</tr>
</tbody>
</table>
</div>
<div id="compat-mobile">
<table class="compat-table">
<tbody>
<tr>
<th>Feature</th>
<th>Android</th>
<th>Chrome for Android</th>
<th>Firefox Mobile (Gecko)</th>
<th>Firefox OS</th>
<th>IE Phone</th>
<th>Opera Mobile</th>
<th>Safari Mobile</th>
</tr>
<tr>
<td>Basic support</td>
<td></td>
<td>{{CompatChrome(40.0)}}</td>
<td>{{ CompatGeckoMobile("44.0") }}</td>
<td>{{ CompatVersionUnknown }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatVersionUnknown() }}</td>
<td>{{ CompatNo() }}</td>
</tr>
<tr>
<td>install/activate events</td>
<td>{{ CompatNo() }}</td>
<td>{{CompatChrome(40.0)}}</td>
<td>{{ CompatGeckoMobile("44.0") }}</td>
<td>{{ CompatVersionUnknown }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatVersionUnknown() }}</td>
<td>{{ CompatNo() }}</td>
</tr>
<tr>
<td>fetch event/request/<br>
<code>respondWith()</code></td>
<td>{{ CompatNo() }}</td>
<td>{{CompatChrome(40.0)}}</td>
<td>{{ CompatGeckoMobile("44.0") }}</td>
<td>{{ CompatVersionUnknown }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
</tr>
<tr>
<td>caches/cache</td>
<td>{{ CompatNo() }}</td>
<td>{{CompatChrome(40.0)}}</td>
<td>{{ CompatGeckoMobile("39.0") }}</td>
<td>{{ CompatVersionUnknown }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
<td>{{ CompatNo() }}</td>
</tr>
</tbody>
</table>
</div>
<p>[1] Service workers (and <a href="/zh-CN/docs/Web/API/Push_API">Push</a>) have been disabled in the <a href="https://www.mozilla.org/en-US/firefox/organizations/">Firefox 45 Extended Support Release</a> (ESR.)</p>
<h2 id="参见">参见</h2>
<ul>
<li><a href="https://serviceworke.rs/">ServiceWorker Cookbook</a></li>
<li><a href="/zh-CN/docs/Web/API/ServiceWorker_API/Using_Service_Workers">Using Service Workers</a></li>
<li><a href="https://github.com/mdn/sw-test">Service workers basic code example</a></li>
<li><a href="https://jakearchibald.github.io/isserviceworkerready/">Is ServiceWorker ready?</a></li>
<li><a href="/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a></li>
<li><a href="/zh-CN/docs/Web/Guide/Performance/Using_web_workers">Using web workers</a></li>
<li><a href="https://www.fastly.com/blog/best-practices-for-using-the-vary-header">Best Practices for using the VARY header</a></li>
</ul>
|