aboutsummaryrefslogtreecommitdiff
path: root/files/id/web/api/service_worker_api
diff options
context:
space:
mode:
Diffstat (limited to 'files/id/web/api/service_worker_api')
-rw-r--r--files/id/web/api/service_worker_api/index.html283
-rw-r--r--files/id/web/api/service_worker_api/using_service_workers/index.html539
2 files changed, 822 insertions, 0 deletions
diff --git a/files/id/web/api/service_worker_api/index.html b/files/id/web/api/service_worker_api/index.html
new file mode 100644
index 0000000000..345f183563
--- /dev/null
+++ b/files/id/web/api/service_worker_api/index.html
@@ -0,0 +1,283 @@
+---
+title: Service Worker API
+slug: Web/API/Service_Worker_API
+tags:
+ - API
+ - Landing
+ - NeedsTranslation
+ - Offline
+ - Overview
+ - Reference
+ - Service Workers
+ - TopicStub
+ - Workers
+translation_of: Web/API/Service_Worker_API
+---
+<div>
+<p>{{ServiceWorkerSidebar}}</p>
+
+<p>{{ SeeCompatTable() }}</p>
+
+<p class="summary">Service workers essentially act as proxy servers that sit between web applications, and the browser and network (when available). They are intended to (amongst other things) enable the creation of effective offline experiences, intercepting network requests and taking appropriate action based on whether the network is available and updated assets reside on the server. They will also allow access to push notifications and background sync APIs.</p>
+</div>
+
+<h2 id="Service_worker_concepts_and_usage">Service worker concepts and usage</h2>
+
+<p>A service worker is an event-driven <a href="https://developer.mozilla.org/en-US/docs/Web/API/Worker">worker</a> registered against an origin and a path. It takes the form of a JavaScript file that can control the web page/site it is associated with, intercepting and modifying navigation and resource requests, and caching resources in a very granular fashion to give you complete control over how your app behaves in certain situations (the most obvious one being when the network is not available.)</p>
+
+<p>A service worker is run in a worker context: it therefore has no DOM access, and runs on a different thread to the main JavaScript that powers your app, so it is not blocking. It is designed to be fully async; as a consequence, APIs such as synchronous <a href="/en-US/docs/Web/API/XMLHttpRequest">XHR</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Storage">localStorage</a> can't be used inside a service worker.</p>
+
+<p>Service workers only run over HTTPS, for security reasons. Having modified network requests wide open to man in the middle attacks would be really bad.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Service Workers win over previous attempts in this area such as <a href="http://alistapart.com/article/application-cache-is-a-douchebag">AppCache</a> because they don't make assumptions about what you are trying to do and then break when those assumptions are not exactly right; you have granular control over everything.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: Service workers make heavy use of <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promises</a>, as generally they will wait for responses to come through, after which they will respond with a success or failure action. The promises architecture is ideal for this.</p>
+</div>
+
+<h3 id="Registration">Registration</h3>
+
+<p>A service worker is first registered using the {{domxref("ServiceWorkerContainer.register()")}} method. If successful, your service worker will be downloaded to the client and attempt installation/activation (see below) for URLs accessed by the user inside the whole origin, or inside a subset specified by you.</p>
+
+<h3 id="Download_install_and_activate">Download, install and activate</h3>
+
+<p>At this point, your service worker will observe the following lifecycle:</p>
+
+<ol>
+ <li>Download</li>
+ <li>Install</li>
+ <li>Activate</li>
+</ol>
+
+<p>The service worker is immediately downloaded when a user first accesses a service worker–controlled site/page.</p>
+
+<p>After that it is downloaded every 24 hours or so. It *may* be downloaded more frequently, but it <strong>must</strong> be downloaded every 24h to prevent bad scripts from being annoying for too long.</p>
+
+<p>Installation is attempted when the downloaded file is found to be new — either different to an existing service worker (byte-wise compared), or the first service worker encountered for this page/site.</p>
+
+<p>If this is the first time a service worker has been made available, installation is attempted, then after a successful installation it is activated.</p>
+
+<p>If there is an existing service worker available, the new version is installed in the background, but not yet activated — at this point it is called the <em>worker in waiting</em>. It is only activated when there are no longer any pages loaded that are still using the old service worker. As soon as there are no more such pages still loaded, the new service worker activates (becoming the <em>active worker</em>).</p>
+
+<p>You can listen out for the {{domxref("InstallEvent")}}; a standard action is to prepare your service worker for usage when this fires, for example by creating a cache using the built in storage API, and placing assets inside it that you'll want for running your app offline.</p>
+
+<p>There is also an <code>activate</code> event. The point where this event fires is generally a good time to clean up old caches and other things associated with the previous version of your service worker.</p>
+
+<p>Your service worker can respond to requests using the {{domxref("FetchEvent")}} event. You can modify the response to these requests in any way you want, using the {{domxref("FetchEvent.respondWith") }} method.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Because <code>oninstall</code>/<code>onactivate</code> could take a while to complete, the service worker spec provides a <code>waitUntil</code> method that, when called <code>oninstall</code> or <code>onactivate</code>, passes a promise. Functional events are not dispatched to the service worker until the promise successfully resolves.</p>
+</div>
+
+<p>For a complete tutorial to show how to build up your first basic example, read <a href="/en-US/docs/Web/API/ServiceWorker_API/Using_Service_Workers">Using Service Workers</a>.</p>
+
+<h2 id="Other_use_case_ideas">Other use case ideas</h2>
+
+<p>Service workers are also intended to be used for such things as:</p>
+
+<ul>
+ <li>Background data synchronization</li>
+ <li>Responding to resource requests from other origins</li>
+ <li>Receiving centralized updates to expensive-to-calculate data such as geolocation or gyroscope, so multiple pages can make use of one set of data</li>
+ <li>Client-side compiling and dependency management of CoffeeScript, less, CJS/AMD modules, etc. for dev purposes</li>
+ <li>Hooks for background services</li>
+ <li>Custom templating based on certain URL patterns</li>
+ <li>Performance enhancements, for example pre-fetching resources that the user is likely to need in the near future, such as the next few pictures in a photo album.</li>
+</ul>
+
+<p>In the future, service workers will be able to do a number of other useful things for the web platform that will bring it closer towards native app viability. Interestingly, other specifications can and will start to make use of the service worker context, for example:</p>
+
+<ul>
+ <li><a href="https://github.com/slightlyoff/BackgroundSync">Background synchronization</a>: Start up a service worker even when no users are at the site, so caches can be updated, etc.</li>
+ <li><a href="/en-US/docs/Web/API/Push_API">Reacting to push messages</a>: Start up a service worker to send users a message to tell them new content is available.</li>
+ <li>Reacting to a particular time &amp; date</li>
+ <li>Entering a geo-fence</li>
+</ul>
+
+<h2 id="Interfaces">Interfaces</h2>
+
+<dl>
+ <dt>{{domxref("Cache") }}</dt>
+ <dd>Represents the storage for {{domxref("Request")}} / {{domxref("Response")}} object pairs that are cached as part of the {{domxref("ServiceWorker")}} life cycle.</dd>
+ <dt>{{domxref("CacheStorage") }}</dt>
+ <dd>Represents the storage for {{domxref("Cache")}} objects. It provides a master directory of all the named caches that a {{domxref("ServiceWorker")}} can access and maintains a mapping of string names to corresponding {{domxref("Cache")}} objects.</dd>
+ <dt>{{domxref("Client") }}</dt>
+ <dd>Represents the scope of a service worker client. A service worker client is either a document in a browser context or a {{domxref("SharedWorker")}}, which is controlled by an active worker.</dd>
+ <dt>{{domxref("Clients") }}</dt>
+ <dd>Represents a container for a list of {{domxref("Client")}} objects; the main way to access the active service worker clients at the current origin.</dd>
+ <dt>{{domxref("ExtendableEvent") }}</dt>
+ <dd>Extends the lifetime of the <code>install</code> and <code>activate</code> events dispatched on the {{domxref("ServiceWorkerGlobalScope")}} as part of the service worker lifecycle. This ensures that any functional events (like {{domxref("FetchEvent")}}) are not dispatched to the {{domxref("ServiceWorker")}} until it upgrades database schemas, deletes outdated cache entries, etc.</dd>
+ <dt>{{domxref("ExtendableMessageEvent") }}</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") }}</dt>
+ <dd>The parameter passed into the {{domxref("ServiceWorkerGlobalScope.onfetch")}} handler, <code>FetchEvent</code> represents a fetch action that is dispatched on the {{domxref("ServiceWorkerGlobalScope")}} of a {{domxref("ServiceWorker")}}. It contains information about the request and resulting response, and provides the {{domxref("FetchEvent.respondWith", "FetchEvent.respondWith()")}} method, which allows us to provide an arbitrary response back to the controlled page.</dd>
+ <dt>{{domxref("InstallEvent") }}</dt>
+ <dd>The parameter passed into the {{domxref("ServiceWorkerGlobalScope.oninstall", "oninstall")}} handler, the <code>InstallEvent</code> interface represents an install action that is dispatched on the {{domxref("ServiceWorkerGlobalScope")}} of a {{domxref("ServiceWorker")}}. As a child of {{domxref("ExtendableEvent")}}, it ensures that functional events such as {{domxref("FetchEvent")}} are not dispatched during installation. </dd>
+ <dt>{{domxref("Navigator.serviceWorker") }}</dt>
+ <dd>Returns a {{domxref("ServiceWorkerContainer")}} object, which provides access to registration, removal, upgrade, and communication with the {{domxref("ServiceWorker")}} objects for the <a href="https://html.spec.whatwg.org/multipage/browsers.html#concept-document-window">associated document</a>.</dd>
+ <dt>{{domxref("NotificationEvent") }}</dt>
+ <dd>The parameter passed into the {{domxref("ServiceWorkerGlobalScope.onnotificationclick", "onnotificationclick")}} handler, the <code>NotificationEvent</code> interface represents a notification click event that is dispatched on the {{domxref("ServiceWorkerGlobalScope")}} of a {{domxref("ServiceWorker")}}.</dd>
+ <dt>{{domxref("ServiceWorker") }}</dt>
+ <dd>Represents a service worker. Multiple browsing contexts (e.g. pages, workers, etc.) can be associated with the same <code>ServiceWorker</code> object.</dd>
+ <dt>{{domxref("ServiceWorkerContainer") }}</dt>
+ <dd>Provides an object representing the service worker as an overall unit in the network ecosystem, including facilities to register, unregister and update service workers, and access the state of service workers and their registrations.</dd>
+ <dt>{{domxref("ServiceWorkerGlobalScope") }}</dt>
+ <dd>Represents the global execution context of a service worker.</dd>
+ <dt>{{domxref("ServiceWorkerMessageEvent")}}</dt>
+ <dd>Contains information about an event sent to a {{domxref("ServiceWorkerContainer")}} target. </dd>
+ <dt>{{domxref("ServiceWorkerRegistration") }}</dt>
+ <dd>Represents a service worker registration.</dd>
+ <dt>{{domxref("SyncEvent")}} {{non-standard_inline}}</dt>
+ <dd>
+ <p>The SyncEvent interface represents a sync action that is dispatched on the {{domxref("ServiceWorkerGlobalScope")}} of a ServiceWorker. </p>
+ </dd>
+ <dt>{{domxref("SyncManager")}} {{non-standard_inline}}</dt>
+ <dd>Provides an interface for registering and listing sync registrations.</dd>
+ <dt>{{domxref("WindowClient") }}</dt>
+ <dd>Represents the scope of a service worker client that is a document in a browser context, controlled by an active worker. This is a special type of {{domxref("Client")}} object, with some additional methods and properties available.</dd>
+</dl>
+
+<h2 id="Specifications">Specifications</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Specification</th>
+ <th scope="col">Status</th>
+ <th scope="col">Comment</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('Service Workers')}}</td>
+ <td>{{Spec2('Service Workers')}}</td>
+ <td>Initial definition.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Browser_compatibility">Browser compatibility</h2>
+
+<div>{{ CompatibilityTable() }}</div>
+
+<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="/en-US/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="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://serviceworke.rs">ServiceWorker Cookbook</a></li>
+ <li><a href="/en-US/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="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a></li>
+ <li><a href="/en-US/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>
diff --git a/files/id/web/api/service_worker_api/using_service_workers/index.html b/files/id/web/api/service_worker_api/using_service_workers/index.html
new file mode 100644
index 0000000000..b88643f6ed
--- /dev/null
+++ b/files/id/web/api/service_worker_api/using_service_workers/index.html
@@ -0,0 +1,539 @@
+---
+title: Menggunakan Service Workers
+slug: Web/API/Service_Worker_API/Using_Service_Workers
+tags:
+ - Paduan
+ - ServiceWorker
+ - dasar
+translation_of: Web/API/Service_Worker_API/Using_Service_Workers
+---
+<p>{{ServiceWorkerSidebar}}</p>
+
+<p>{{ SeeCompatTable() }}</p>
+
+<div class="summary">
+<p>Artikel ini memberikan informasi mengenai cara memulai dan menggunakan Service Workers, Termasuk arsitektur dasar, mendaftarkan service worker, penginstalan dan proses aktivasi service worker, memperbaharui service worker, kontrol cache dan custom response, Semuanya dalam konteks aplikasi sederhana dengan fungsi offline. </p>
+</div>
+
+<h2 id="Premis_Service_Workers">Premis Service Workers</h2>
+
+<p>Salah satu masalah utama yang dialami pengguna web selama bertahun - tahun adalah hilangnya konektivitas. Bahkan aplikasi terbaik didunia sekalipun akan memberikan pengalaman pengguna yang buruk jika tidak bisa di muat atau di download. Berbagai upaya menciptakan teknologi telah dilakukan untuk memecahkan masalah tersebut, Agar halaman <a href="/en-US/Apps/Build/Offline">Offline</a> dapat digunakan, dan beberapa masalah telah diselesaikan.Tapi masalah utamanya masih belum ada mekanisame kontrol yang terbaik untuk semua permintaan aset cache dan kostum jaringan.<br>
+ <br>
+ Pada upaya sebelumnya — AppCache — dilihat sebagai ide yang bagus karena disana anda juga bisa menentukan aset untuk dicache dengan mudah. Namun, itu membuat asumsi tentang ketika anda mencoba dan kemudian pecah dengan mengerikan ketika aplikasi anda tidak mengikuti asumsi premis. Baca artikel Jake Archibald's <a href="http://alistapart.com/article/application-cache-is-a-douchebag">Application Cache is a Douchebag</a> untuk lebih detail.</p>
+
+<div class="note">
+<p><strong>Catatan</strong>: Pada firefox 44, ketika <a href="/en-US/docs/Web/HTML/Using_the_application_cache">AppCache</a> digunakan untuk menyediakan layanan offline untuk suatu halaman, pesan peringatan sekarang akan ditampilkan di console menyarankan pengembang untuk menggunakan <a href="/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers">Service workers</a>  ({{bug("1204581")}}.)</p>
+</div>
+
+<p>Service worker seharusnya telah memecahkan masalah ini. Syntax pada service worker lebih kompleks di bandingkan AppCache, tapi kesamaanya adalah anda bisa menggunkan javascript untuk mengontrol AppCache anda secara tersirat dengan derajat grunality yang lebih bagus, memungkinkan anda untuk menangani masalah ini dan banyak lagi. Dengan menggunakan Service worker anda bisa mengatur aplikasi untuk menggunakan aset utama, sehingga memberikan pengalaman utama bahkan saat offline, sebelum mendapatkan lebih banyak data dari jaringan (biasa disebut sebagai <a href="http://offlinefirst.org/">Offline First</a>). Ini sudah tersedia dengan aplikasi asli, yang merupakan salah satu alasan utama aplikasi asli sering dipilih lebih dari aplikasi web.</p>
+
+<h2 id="Persiapan_bermain_dengan_service_worker">Persiapan bermain dengan service worker</h2>
+
+<p>Banyak fitur service worker saat ini telah di aktifkan secara default pada browser versi terbaru yang mendukung. Tapi jika anda menemui kode demo tidak bekerja pada versi browser anda, mungkin anda perlu mengaktifkan preferensi:</p>
+
+<ul>
+ <li><strong>Firefox Nightly</strong>: Buka <code>about:config</code> dan atur  <code>dom.serviceWorkers.enabled</code> ke true; kemudian restart browser.</li>
+ <li><strong>Chrome Canary</strong>: Buka <code>chrome://flags</code> dan aktifkan <code>experimental-web-platform-features</code>; restart browser ( perlu dicatat bahwa beberapa fitur telah diaktifkan secara default di Chrome.)</li>
+ <li><strong>Opera</strong>: Buka <code>opera://flags</code> dan aktifkan dukungan untuk<code> ServiceWorker</code>; restart browser.</li>
+</ul>
+
+<p>Anda perlu menyajikan kode dengan menggunakan HTTPS — Service Workers dibatasi dengan hanya dapat di jalankan pada HTTPS untuk alasan keamanan. Github merupakan salah satu tempat yang di sarankan untuk bereksperimen, karena mendukung HTTPS.</p>
+
+<h2 id="Arsitektur_dasar">Arsitektur dasar</h2>
+
+<p>Dengan service workers, langkah - langkah umum berikut perlu diamati untuk konfigurasi dasar:</p>
+
+<ol>
+ <li>URL service worker diambil di daftarkan melalui {{domxref("serviceWorkerContainer.register()")}}.</li>
+ <li>Jika sukses, service worker dijalankan di {{domxref("ServiceWorkerGlobalScope") }}; pada dasarnya ini merupakan hal yang sepesial dari konteks worker, menjalankan tread script utama untuk pengeksekusian, tanpa dukungan akses DOM.</li>
+ <li>Sekarang service worker telah siap untuk memproses event.</li>
+ <li>Instalasai service worker dicoba ketika service worker mengontrol halaman yang diakses setelah dan sebelumnya. Even Install akan selalu di kirim pertama kali ke service workerr ( ini bisa digunakan untuk memulai proses untuk mengumpulkan IndexedDB, dan mencache aset situs). Sama halnya seperti prosedur penginstalan asli atau aplikasi firefox OS — memungkinkan semuanya tersedia untuk digunakan secara offline.</li>
+ <li>Ketika handler <code>oninstall</code> selesai, service worker ditetapkan untuk diinstall.</li>
+ <li>Selanjutnya adalah aktivasi. Ketika service worker terinstall, selanjutnya akan menerima event activate. Penggunaan utama dari <code>onactivate</code> adalah untuk membersihkan sumberdaya yang digunakan pada versi sebelumnya.</li>
+ <li>Service Worker sekarang dapat mengontrol halaman, tapi hanya yang di buka setelah <code>register()</code> telah sukses. misal dokumen mulai aktif dengan atau tanpa Service Worker dan menjaganya selama masih digunakan. Jadi dokumen harus di muat ulang agar benar - benar terkontrol.</li>
+</ol>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/12636/sw-lifecycle.png" style="display: block; height: 867px; margin: 0px auto; width: 579px;"></p>
+
+<p>Grafik dibawah menunjukan ringkasan dari event yang tersedia pada service worker:</p>
+
+<p><img alt="install, activate, message, fetch, sync, push" src="https://mdn.mozillademos.org/files/12632/sw-events.png" style="display: block; margin: 0px auto;"></p>
+
+<h3 id="Promis">Promis</h3>
+
+<p><a href="/id/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promis</a> adalah mekanisme yang sebagian besar digunakan untuk menjalankan operasi secara asinkron, dengan bergantung pada pencapaian satu dan lainnya. Ini merupakan pusat dari cara kerja service workers.<br>
+ <br>
+ Promis bisa digunakan untuk melakukan banyak hal, tapi untuk saat ini, yang perlu anda tahu adalah jika sesuatu yang mengembalikan promise, anda bisa menambahkan<code>.then()</code> di akhir dan menambahkan callback di dalamnya untuk mengetahui apakah berhasil, gagal da lainnya., atau anda bisa menambahkan <code>.catch()</code> di akhir jika anda ingin menambahkan calback status gagal.</p>
+
+<p>Mari bandingkan kesamaan struktur callback tradisional synchronous dan promise asynchronous.</p>
+
+<h4 id="sync">sync</h4>
+
+<pre class="brush: js">try {
+ var value = myFunction();
+ console.log(value);
+} catch(err) {
+ console.log(err);
+}</pre>
+
+<h4 id="async">async</h4>
+
+<pre class="brush: js">myFunction().then(function(value) {
+ console.log(value);
+ }).catch(function(err) {
+ console.log(err);
+});</pre>
+
+<p>Pada contoh pertama, kita perlu mengunggu <code>myFunction()</code> untuk dijalankan dan mengembalikan nilai sebelum kode lain bisa dijalankan. Pada contoh kedua, <code>myFunction()</code> mengembalikan promise untuk <code>nilai</code>, kemudian semua kode dapat di bawa untuk dapat dijalankan. Ketika promise diselesaikan, kode didalamnya bisa dijalankan secara asynchronously.<br>
+ <br>
+ Sebagai contoh nyata — jika kita ingin memuat gambar secara dinamic, tapi kita ingin memastikan bahwa gambar tersebut di muat terlebih dahulu sebelum di tampilkan? Hal standar ini yang ingin dilakukan, tapi ini akan sedikit sulit. Kita bisa mengunakan <code>.onload</code> untuk hanya menampilkan gambar setelah di muat, tapi bagaimana dengan event yang memulai sebelum kita memulai melacaknya ? kita bisa mencoba melakukannya dengan menggunakan<code>.complete</code>, tapi ini tetap tidak foolproof, dan bagaimana dengan lebih dari satu gambar? Dan, ummm, ini tetap synchronous, Jadi di blok di tread utama.<br>
+ <br>
+ Gantinya, kita bisa membuat promis kita sendiri untuk mengatasi kasus seperi ini. (Lihat contoh <a href="https://github.com/mdn/promises-test">Promises test</a> untuk kode sumber, atau <a href="https://mdn.github.io/promises-test/">Lihat cara kerja secara live</a>.)</p>
+
+<p>{{note("Implementasi service worker akan mengutamakan menggunakan caching dan onfetch daripada XMLHttpRequest API. Fitur tersebut tidak di gunakan disini jadi anda hanya fokus pada penggunaan Promises.")}}</p>
+
+<pre class="brush: js">function imgLoad(url) {
+ return new Promise(function(resolve, reject) {
+ var request = new XMLHttpRequest();
+ request.open('GET', url);
+ request.responseType = 'blob';
+
+ request.onload = function() {
+ if (request.status == 200) {
+ resolve(request.response);
+ } else {
+ reject(Error('Image didn\'t load successfully; error code:' + request.statusText));
+ }
+ };
+
+ request.onerror = function() {
+ reject(Error('There was a network error.'));
+ };
+
+ request.send();
+ });
+}</pre>
+
+<p>Kita mengembalikan promis baru menggunakan konstruktor <code>Promise()</code>, di mana menggunakan argumen sebagai fungsi callback dengan parameter <code>resolve</code> dan <code>reject</code>. DImanapung di fungsi, kita perlu mendefinisikan apa yang terjadi untuk promise yang diselesaikan secara sukses atau ditolak — pada kasus ini mengembalikan status 200 OK atau tidak — dan kemudian memanggil  <code>resolve</code> ketika sukses, atau <code>reject</code> jika gagal. Semua konten dari fungsi ini adalah perangkat dasar XHR, jadi kita tidak perlu khawatir untuk saat ini.</p>
+
+<p>Ketika memanggil fungsi <code>imgLoad()</code>, kita memanggilnya dengan menggunakan url gambar yang akan dimuat, seperti yang kita harapkan, namun kodenya sedikit berbeda:</p>
+
+<pre class="brush: js">var body = document.querySelector('body');
+var myImage = new Image();
+
+imgLoad('myLittleVader.jpg').then(function(response) {
+ var imageURL = window.URL.createObjectURL(response);
+ myImage.src = imageURL;
+ body.appendChild(myImage);
+}, function(Error) {
+ console.log(Error);
+});</pre>
+
+<p>Pada akhir pemanggilan fungsi, kita menggabungkan promise method <code>then()</code>, dimana terdiri dari dua fungsi — yang pertama akan di eksekusi ketika promise berhasil di selesaikan, dan yang kedua akan dipanggil ketika promise di tolak. Pada penyelesaian kasus, kita menampilkan gambar di dalam <code>myImage</code> dan menambahkannya ke body (dengan argumen <code>request.response</code> yang berada di dalam method <code>resolve</code>); pada kasus ditolak kita mengembalikan error di console.</p>
+
+<p>Semua terjadi secara asynchronously.</p>
+
+<div class="note">
+<p><strong>Catatan</strong>: Anda juga bisa menggabungkan panggilan promise secara bersamaan, Misal:<br>
+ <code>myPromise().then(success, failure).then(success).catch(failure);</code></p>
+</div>
+
+<div class="note">
+<p><strong>Catatan</strong>: Anda bisa mendapatkan lebih banyak informasi tentang promise dengan membaca tulisan Jake Archibald’s excellent <a href="http://www.html5rocks.com/en/tutorials/es6/promises/">JavaScript Promises: there and back again</a>.</p>
+</div>
+
+<h2 id="Demo_service_workers">Demo service workers</h2>
+
+<p>Sebagai demonstrasi hanya sekedar dasar pendaftaran dan penginstalan service worker, kita membuat sebuah demo sederhana dengan nama <a href="https://github.com/mdn/sw-test">sw-test</a>, berupa galeri gambar Star wars Lego. Mengunakan fungsi dengan promise untuk membaca data gambar dari sebuah objek JSON dan memuat gambar menggunakan Ajax, Sebelum menamilkan gambar pada halaman. Kita akan semuanya tetap simple dan statis untuk saat ini. Di sini pendaftaran, instalasi, dan akativasi sebuah service worker, dan ketika semua spec di dukung oleh browsers maka semua file yang diperukan akan dicache untuk di muat secara offline!</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/8243/demo-screenshot.png" style="display: block; height: 410px; margin: 0px auto; width: 480px;"><br>
+ <br>
+ <br>
+ Anda bisa melihat <a href="https://github.com/mdn/sw-test/">source code di GitHub</a>, dan <a href="https://mdn.github.io/sw-test/">Melihat contoh secara live</a>. The one bit we’ll call out here is the promise (see <a href="https://github.com/mdn/sw-test/blob/gh-pages/app.js#L17-L42">app.js lines 17-42</a>), which is a modified version of what you read about above, in the <a href="https://github.com/mdn/promises-test">Promises test demo</a>. It is different in the following ways:</p>
+
+<ol>
+ <li>In the original, we only passed in a URL to an image we wanted to load. In this version, we pass in a JSON fragment containing all the data for a single image (see what they look like in <a href="https://github.com/mdn/sw-test/blob/gh-pages/image-list.js">image-list.js</a>). This is because all the data for each promise resolve has to be passed in with the promise, as it is asynchronous. If you just passed in the url, and then tried to access the other items in the JSON separately when the <code>for()</code> loop is being iterated through later on, it wouldn’t work, as the promise wouldn’t resolve at the same time as the iterations are being done (that is a synchronous process.)</li>
+ <li>We actually resolve the promise with an array, as we want to make the loaded image blob available to the resolving function later on in the code, but also the image name, credits and alt text (see <a href="https://github.com/mdn/sw-test/blob/gh-pages/app.js#L26-L29">app.js lines 26-29</a>). Promises will only resolve with a single argument, so if you want to resolve with multiple values, you need to use an array/object.</li>
+ <li>To access the resolved promise values, we then access this function as you’d then expect (see <a href="https://github.com/mdn/sw-test/blob/gh-pages/app.js#L55-L59">app.js lines 55-59</a>.) This may seem a bit odd at first, but this is the way promises work.</li>
+</ol>
+
+<h2 id="Enter_Service_workers">Enter Service workers</h2>
+
+<p>Now let’s get on to service workers!</p>
+
+<h3 id="Mendaftarkan_worker">Mendaftarkan worker</h3>
+
+<p>The first block of code in our app’s JavaScript file — <code>app.js</code> — is as follows. This is our entry point into using service workers.</p>
+
+<pre class="brush: js">if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/sw-test/' }).then(function(reg) {
+ // registration worked
+ console.log('Registration succeeded. Scope is ' + reg.scope);
+ }).catch(function(error) {
+ // registration failed
+ console.log('Registration failed with ' + error);
+ });
+};</pre>
+
+<ol>
+ <li>The outer block performs a feature detection test to make sure service workers are supported before trying to register one.</li>
+ <li>Next, we use the {{domxref("ServiceWorkerContainer.register()") }} function to register the service worker for this site, which is just a JavaScript file residing inside our app (note this is the file's URL relative to the origin, not the JS file that references it.)</li>
+ <li>The <code>scope</code> parameter is optional, and can be used to specify the subset of your content that you want the service worker to control. In this case, we have specified '<code>/sw-test/'</code>, which means all content under the app's origin. If you leave it out, it will default to this value anyway, but we specified it here for illustration purposes.</li>
+ <li>The <code>.then()</code> promise function is used to chain a success case onto our promise structure.  When the promise resolves successfully, the code inside it executes.</li>
+ <li>Finally, we chain a <code>.catch()</code> function onto the end that will run if the promise is rejected.</li>
+</ol>
+
+<p>This registers a service worker, which runs in a worker context, and therefore has no DOM access. You then run code in the service worker outside of your normal pages to control their loading.<br>
+ <br>
+ A single service worker can control many pages. Each time a page within your scope is loaded, the service worker is installed against that page and operates on it. Bear in mind therefore that you need to be careful with global variables in the service worker script: each page doesn’t get its own unique worker.</p>
+
+<div class="note">
+<p><strong>Note</strong>: Your service worker functions like a proxy server, allowing you to modify requests and responses, replace them with items from its own cache, and more.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: One great thing about service workers is that if you use feature detection like we’ve shown above, browsers that don’t support service workers can just use your app online in the normal expected fashion. Furthermore, if you use AppCache and SW on a page, browsers that don’t support SW but do support AppCache will use that, and browsers that support both will ignore the AppCache and let SW take over.</p>
+</div>
+
+<h4 id="Kenapa_service_worker_saya_gagal_didaftarkan">Kenapa service worker saya gagal didaftarkan?</h4>
+
+<p>Hal tersebut bisa terjadi karena alasan berikut:</p>
+
+<ol>
+ <li>Anda tidak menjalankan aplikasi dari HTTPS.</li>
+ <li>Path dari file service worker anda tidak ditulis dengan benar — seharusnya di tulis relatif terhadap origin, bukan root dari direktori aplikasi anda. Pada contoh, worker berada di <code>https://mdn.github.io/sw-test/sw.js</code>, dan root aplikasi di <code>https://mdn.github.io/sw-test/</code>. Namun path harus ditulis <code>/sw-test/sw.js</code>, bukan <code>/sw.js</code>.</li>
+ <li>The service worker being pointed to is on a different origin to that of your app. This is also not allowed.</li>
+</ol>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/12630/important-notes.png" style="display: block; height: 277px; margin: 0px auto; width: 574px;"></p>
+
+<p>Also note:</p>
+
+<ul>
+ <li>The service worker will only catch requests from clients under the service worker's scope.</li>
+ <li>The max scope for a service worker is the location of the worker.</li>
+ <li>If your server worker is active on a client being served with the <code>Service-Worker-Allowed</code> header, you can specify a list of max scopes for that worker.</li>
+ <li>In Firefox, Service Worker APIs are hidden and cannot be used when the user is in <a href="https://support.mozilla.org/en-US/kb/private-browsing-use-firefox-without-history">private browsing mode</a>.</li>
+</ul>
+
+<h3 id="Install_dan_activasi_mengumpulkan_cache">Install dan activasi: mengumpulkan cache</h3>
+
+<p>Setelah service worker anda terdaftar, browser akan menginstall dan mengaktifkan service worker untuk halaman/situs anda.<br>
+ <br>
+ Event instal dijalankan ketika install selesai dengan sukses. Event install biasanya digunakan oleh browser untuk mengumpulkan cache offline dari aset yang akan digunakan untuk menjalankan aplikasi anda secara offline. Untuk melakukannya, kita menggunakan Storage API dari Service Worker — {{domxref("cache")}} —  global pada service worker yang memungkinkan kita menympan aset yang diterima dari response, dan di sandikan berdasarkan request. API ini sama halnya dengan cache pada browser umumnya, tapi lebih spesifik ke domain. Ini persis hinga anda tidak menginginkan — anda punya kontrol penuh.</p>
+
+<div class="note">
+<p><strong>Note</strong>: The Cache API is not supported in every browser. (See the {{anch("Browser support")}} section for more information.) If you want to use this now, you could consider using a polyfill like the one available in <a href="https://github.com/Polymer/topeka/blob/master/sw.js">Google's Topeka demo</a>, or perhaps store your assets in <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a>.</p>
+</div>
+
+<p>Let’s start this section by looking at a code sample — this is the <a href="https://github.com/mdn/sw-test/blob/gh-pages/sw.js#L1-L18">first block you’ll find in our service worker</a>:</p>
+
+<pre class="brush: js">this.addEventListener('install', function(event) {
+  event.waitUntil(
+    caches.open('v1').then(function(cache) {
+      return cache.addAll([
+        '/sw-test/',
+        '/sw-test/index.html',
+        '/sw-test/style.css',
+        '/sw-test/app.js',
+        '/sw-test/image-list.js',
+        '/sw-test/star-wars-logo.jpg',
+        '/sw-test/gallery/',
+        '/sw-test/gallery/bountyHunters.jpg',
+        '/sw-test/gallery/myLittleVader.jpg',
+        '/sw-test/gallery/snowTroopers.jpg'
+      ]);
+    })
+  );
+});</pre>
+
+<ol>
+ <li>Here we add an <code>install</code> event listener to the service worker (hence <code>this</code>), and then chain a {{domxref("ExtendableEvent.waitUntil()") }} method onto the event — this ensures that the Service Worker will not install until the code inside <code>waitUntil()</code> has successfully occurred.</li>
+ <li>Inside <code>waitUntil()</code> we use the <a href="/en-US/docs/Web/API/CacheStorage/open"><code>caches.open()</code></a> method to create a new cache called <code>v1</code>, which will be version 1 of our site resources cache. This returns a promise for a created cache; once resolved, we then call a function that calls <code>addAll()</code> on the created cache, which for its parameter takes an array of origin-relative URLs to all the resources you want to cache.</li>
+ <li>If the promise is rejected, the install fails, and the worker won’t do anything. This is ok, as you can fix your code and then try again the next time registration occurs.</li>
+ <li>After a successful installation, the service worker activates. This doesn’t have much of a distinct use the first time your service worker is installed/activated, but it means more when the service worker is updated (see the {{anch("Updating your service worker") }} section later on.)</li>
+</ol>
+
+<div class="note">
+<p><strong>Note</strong>: <a href="/en-US/docs/Web/Guide/API/DOM/Storage">localStorage</a> works in a similar way to service worker cache, but it is synchronous, so not allowed in service workers.</p>
+</div>
+
+<div class="note">
+<p><strong>Note</strong>: <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB</a> can be used inside a service worker for data storage if you require it.</p>
+</div>
+
+<h3 id="Custom_responses_to_requests">Custom responses to requests</h3>
+
+<p>Now you’ve got your site assets cached, you need to tell service workers to do something with the cached content. This is easily done with the <code>fetch</code> event.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/12634/sw-fetch.png" style="display: block; margin: 0 auto;"></p>
+
+<p>A <code>fetch</code> event fires every time any resource controlled by a service worker is fetched, which includes the documents inside the specified scope, and any resources referenced in those documents (for example if <code>index.html</code> makes a cross origin request to embed an image, that still goes through its service worker.)</p>
+
+<p>You can attach a <code>fetch</code> event listener to the service worker, then call the <code>respondWith()</code> method on the event to hijack our HTTP responses and update them with your own magic.</p>
+
+<pre class="brush: js">this.addEventListener('fetch', function(event) {
+ event.respondWith(
+ // magic goes here
+ );
+});</pre>
+
+<p>We could start by simply responding with the resource whose url matches that of the network request, in each case:</p>
+
+<pre class="brush: js">this.addEventListener('fetch', function(event) {
+ event.respondWith(
+ caches.match(event.request);
+ );
+});</pre>
+
+<p><code>caches.match(event.request)</code> allows us to match each resource requested from the network with the equivalent resource available in the cache, if there is a matching one available. The matching is done via url and vary headers, just like with normal HTTP requests.</p>
+
+<p>Let’s look at a few other options we have when defining our magic (see our <a href="/en-US/docs/Web/API/Fetch_API">Fetch API documentation</a> for more information about {{domxref("Request")}} and {{domxref("Response")}} objects.)</p>
+
+<ol>
+ <li>
+ <p>The <code>{{domxref("Response.Response","Response()")}}</code> constructor allows you to create a custom response. In this case, we are just returning a simple text string:</p>
+
+ <pre class="brush: js">new Response('Hello from your friendly neighbourhood service worker!');</pre>
+ </li>
+ <li>
+ <p>This more complex <code>Response</code> below shows that you can optionally pass a set of headers in with your response, emulating standard HTTP response headers. Here we are just telling the browser what the content type of our synthetic response is:</p>
+
+ <pre class="brush: js">new Response('</pre>
+
+ <p>Hello from your friendly neighbourhood service worker!</p>
+ ', { headers: { 'Content-Type': 'text/html' } })</li>
+ <li>
+ <p>If a match wasn’t found in the cache, you could tell the browser to simply {{domxref("GlobalFetch.fetch","fetch")}} the default network request for that resource, to get the new resource from the network if it is available:</p>
+
+ <pre class="brush: js">fetch(event.request)</pre>
+ </li>
+ <li>
+ <p>If a match wasn’t found in the cache, and the network isn’t available, you could just match the request with some kind of default fallback page as a response using {{domxref("CacheStorage.match","match()")}}, like this:</p>
+
+ <pre class="brush: js">caches.match('/fallback.html');</pre>
+ </li>
+ <li>
+ <p>You can retrieve a lot of information about each request by calling parameters of the {{domxref("Request")}} object returned by the {{domxref("FetchEvent")}}:</p>
+
+ <pre class="brush: js">event.request.url
+event.request.method
+event.request.headers
+event.request.body</pre>
+ </li>
+</ol>
+
+<h2 id="Recovering_failed_requests">Recovering failed requests</h2>
+
+<p>So <code>caches.match(event.request)</code> is great when there is a match in the service worker cache, but what about cases when there isn’t a match? If we didn’t provide any kind of failure handling, our promise would reject and we would just come up against a network error when a match isn’t found.</p>
+
+<p>Fortunately service workers’ promise-based structure makes it trivial to provide further options towards success. We could do this:</p>
+
+<pre class="brush: js">this.addEventListener('fetch', function(event) {
+ event.respondWith(
+ caches.match(event.request).catch(function() {
+ return fetch(event.request);
+ })
+ );
+});</pre>
+
+<p>If the promise rejects, the <code>catch()</code> function returns the default network request for the resource instead, meaning that those who have network available can just load the resource from the server.</p>
+
+<p>If we were being really clever, we would not only request the resource from the network; we would also save it into the cache so that later requests for that resource could be retrieved offline too! This would mean that if extra images were added to the Star Wars gallery, our app could automatically grab them and cache them. The following would do the trick:</p>
+
+<pre class="brush: js">this.addEventListener('fetch', function(event) {
+ event.respondWith(
+ caches.match(event.request).catch(function() {
+ return fetch(event.request).then(function(response) {
+ return caches.open('v1').then(function(cache) {
+ cache.put(event.request, response.clone());
+ return response;
+ });
+ });
+ })
+ );
+});</pre>
+
+<p>Here we return the default network request with <code>return fetch(event.request)</code>, which returns a promise. When this promise is resolved, we respond by running a function that grabs our cache using <code>caches.open('v1')</code>; this also returns a promise. When that promise resolves, <code>cache.put()</code> is used to add the resource to the cache. The resource is grabbed from <code>event.request</code>, and the response is then cloned with <code>response.clone()</code> and added to the cache. The clone is put in the cache, and the original response is returned to the browser to be given to the page that called it.</p>
+
+<p>Why? This is because request and response streams can only be read once.  In order to return the response to the browser and put it in the cache we have to clone it. So the original gets returned to the browser and the clone gets sent to the cache.  They are each read once.</p>
+
+<p>The only trouble we have now is that if the request doesn’t match anything in the cache, and the network is not available, our request will still fail. Let’s provide a default fallback so that whatever happens, the user will at least get something:</p>
+
+<pre class="brush: js">this.addEventListener('fetch', function(event) {
+ event.respondWith(
+ caches.match(event.request).catch(function() {
+ return fetch(event.request).then(function(response) {
+ return caches.open('v1').then(function(cache) {
+ cache.put(event.request, response.clone());
+ return response;
+ });
+ });
+ }).catch(function() {
+    return caches.match('/sw-test/gallery/myLittleVader.jpg');
+  })
+ );
+});</pre>
+
+<p>We have opted for this fallback image because the only updates that are likely to fail are new images, as everything else is depended on for installation in the <code>install</code> event listener we saw earlier.</p>
+
+<h2 id="Updated_code_pattern_suggestion">Updated code pattern suggestion</h2>
+
+<p>This uses more standard promise chaining and returns the response to the document without having to wait for <code>caches.open()</code> to resolve:</p>
+
+<pre class="brush: js">this.addEventListener('fetch', function(event) {
+  var response;
+  event.respondWith(caches.match(event.request).catch(function() {
+    return fetch(event.request);
+  }).then(function(r) {
+    response = r;
+    caches.open('v1').then(function(cache) {
+      cache.put(event.request, response);
+    });
+    return response.clone();
+  }).catch(function() {
+    return caches.match('/sw-test/gallery/myLittleVader.jpg');
+  }));
+});</pre>
+
+<h2 id="Membaharui_service_worker"><a id="Updating your service worker" name="Updating your service worker">Membaharui service worker</a></h2>
+
+<p>If your service worker has previously been installed, but then a new version of the worker is available on refresh or page load, the new version is installed in the background, but not yet activated. It is only activated when there are no longer any pages loaded that are still using the old service worker. As soon as there are no more such pages still loaded, the new service worker activates.</p>
+
+<p>You’ll want to update your <code>install</code> event listener in the new service worker to something like this (notice the new version number):</p>
+
+<pre class="brush: js">this.addEventListener('install', function(event) {
+ event.waitUntil(
+ caches.open('v2').then(function(cache) {
+ return cache.addAll([
+ '/sw-test/',
+ '/sw-test/index.html',
+ '/sw-test/style.css',
+ '/sw-test/app.js',
+ '/sw-test/image-list.js',
+
+ …
+
+ // include other new resources for the new version...
+ ]);
+ });
+ );
+});</pre>
+
+<p>While this happens, the previous version is still responsible for fetches. The new version is installing in the background. We are calling the new cache <code>v2</code>, so the previous <code>v1</code> cache isn't disturbed.</p>
+
+<p>When no pages are using the current version, the new worker activates and becomes responsible for fetches.</p>
+
+<h3 id="Deleting_old_caches">Deleting old caches</h3>
+
+<p>You also get an <code>activate</code> event. This is a generally used to do stuff that would have broken the previous version while it was still running, for example getting rid of old caches. This is also useful for removing data that is no longer needed to avoid filling up too much disk space — each browser has a hard limit on the amount of cache storage that a given service worker can use. The browser does its best to manage disk space, but it may delete the Cache storage for an origin.  The browser will generally delete all of the data for an origin or none of the data for an origin.</p>
+
+<p>Promises passed into <code>waitUntil()</code> will block other events until completion, so you can rest assured that your clean-up operation will have completed by the time you get your first <code>fetch</code> event on the new cache.</p>
+
+<pre class="brush: js">this.addEventListener('activate', function(event) {
+ var cacheWhitelist = ['v2'];
+
+ event.waitUntil(
+ caches.keys().then(function(keyList) {
+ return Promise.all(keyList.map(function(key) {
+ if (cacheWhitelist.indexOf(key) === -1) {
+ return caches.delete(key);
+ }
+ }));
+ })
+ );
+});</pre>
+
+<h2 id="Dev_tools">Dev tools</h2>
+
+<p>Chrome has <code>chrome://inspect/#service-workers</code>, which shows current service worker activity and storage on a device, and <code>chrome://serviceworker-internals</code>, which shows more detail and allows you to start/stop/debug the worker process. In the future they will have throttling/offline modes to simulate bad or non-existent connections, which will be a really good thing.</p>
+
+<p>Firefox has also started to implement some useful tools related to service workers:</p>
+
+<ul>
+ <li>You can navigate to <a>about:serviceworkers</a> to see what SWs are registered and update/remove them.</li>
+ <li>When testing you can get around the HTTPS restriction by checking the "Enable Service Workers over HTTP (when toolbox is open)" option in the Firefox Devtools options (gear menu.)</li>
+</ul>
+
+<h2 id="Spesifikasi">Spesifikasi</h2>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <th scope="col">Spesifikasi</th>
+ <th scope="col">Status</th>
+ <th scope="col">Comment</th>
+ </tr>
+ <tr>
+ <td>{{SpecName('Service Workers', '')}}</td>
+ <td>{{Spec2('Service Workers')}}</td>
+ <td>Initial definition.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Browser_compatibility">Browser compatibility</h2>
+
+<div>{{CompatibilityTable}}</div>
+
+<div id="compat-desktop">
+<table class="compat-table">
+ <tbody>
+ <tr>
+ <th>Fitur</th>
+ <th>Chrome</th>
+ <th>Firefox (Gecko)</th>
+ <th>Internet Explorer</th>
+ <th>Opera</th>
+ <th>Safari (WebKit)</th>
+ </tr>
+ <tr>
+ <td>Dukungan dasar</td>
+ <td>{{CompatChrome(40.0)}}</td>
+ <td>{{ CompatGeckoDesktop("33.0") }}<sup>[1]</sup></td>
+ <td>{{CompatNo}}</td>
+ <td>24</td>
+ <td>{{CompatNo}}</td>
+ </tr>
+ </tbody>
+</table>
+</div>
+
+<div id="compat-mobile">
+<table class="compat-table">
+ <tbody>
+ <tr>
+ <th>Fitur</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>Dukungan dasar</td>
+ <td>{{CompatNo}}</td>
+ <td>{{CompatChrome(40.0)}}</td>
+ <td>{{ CompatVersionUnknown }}</td>
+ <td>{{ CompatVersionUnknown }}</td>
+ <td>{{CompatNo}}</td>
+ <td>{{ CompatVersionUnknown() }}</td>
+ <td>{{CompatNo}}</td>
+ </tr>
+ </tbody>
+</table>
+</div>
+
+<p>[1] Service workers (and <a href="/en-US/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="Lihat_juga">Lihat juga</h2>
+
+<ul>
+ <li><a href="https://serviceworke.rs/">The Service Worker Cookbook</a></li>
+ <li><a href="https://jakearchibald.github.io/isserviceworkerready/">Is ServiceWorker ready?</a></li>
+ <li>Download the <a href="https://mdn.mozillademos.org/files/12638/sw101.png">Service Workers 101 cheatsheet</a>.</li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a></li>
+ <li><a href="/en-US/docs/Web/Guide/Performance/Using_web_workers">Using web workers</a></li>
+</ul>