<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] # Service Workers 豐富的離線體驗、定期的后臺同步以及推送通知等通常需要將面向本機應用的功能將引入到網絡應用中。service worker提供了所有這些功能所依賴的技術基礎。 <br> ## 什么是service worker service worker是瀏覽器在后臺獨立于網頁運行的腳本,它打開了通向不需要網頁或用戶交互的功能的大門。現在,它們已包括如推送通知和后臺同步等功能。將來,service worker將會支持如定期同步或地理圍欄等其他功能。本教程討論的核心功能是攔截和處理網絡請求,包括通過程序來管理緩存中的響應。 這個 API 之所以令人興奮,是因為它可以支持離線體驗,讓開發者能夠全面控制這一體驗。 在service worker出現前,存在能夠在網絡上為用戶提供離線體驗的另一個 API,稱為 AppCache。App Cache 的主要問題是,它具有相當多的缺陷,并且,雖然它對單頁網絡應用支持較好,但對多頁網站來說則不盡人意。service worker則能很好地避免這些常見的難點。 service worker相關注意事項: * 它是一種 [JavaScript 工作線程](https://www.html5rocks.com/en/tutorials/workers/basics/),無法直接訪問 DOM。 service worker通過響應 [`postMessage`](https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage) 接口發送的消息來與其控制的頁面通信,頁面可在必要時對 DOM 執行操作。 * service worker是一種可編程網絡代理,讓您能夠控制頁面所發送網絡請求的處理方式。 * 它在不用時會被中止,并在下次有需要時重啟,因此,您不能依賴于service worker的 `onfetch` 和 `onmessage` 處理程序中的全局狀態。如果存在您需要持續保存并在重啟后加以重用的信息,service worker可以訪問 [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)。 * service worker廣泛地利用了 `promise`,因此如果您不熟悉 `promise`,則應停下閱讀此內容,看一看 Promise 簡介。 <br> ## service worker生命周期 service worker的生命周期完全獨立于網頁。 要為網站安裝service worker,您需要先在頁面的 JavaScript 中注冊。 注冊service worker將會導致瀏覽器在后臺啟動服務工作線程安裝步驟。 在安裝過程中,您通常需要緩存某些靜態資源。如果所有文件均已成功緩存,那么service worker就安裝完畢。如果任何文件下載失敗或緩存失敗,那么安裝步驟將會失敗,service worker就無法激活(也就是說,不會安裝)。 如果發生這種情況,不必擔心,它下次會再試一次。 但這意味著,如果安裝完成,您可以知道您已在緩存中獲得那些靜態資源。 安裝之后,接下來就是激活步驟,這是管理舊緩存的絕佳機會,我們將在service worker的更新部分對此詳加介紹。 激活之后,service worker將會對其作用域內的所有頁面實施控制,不過,首次注冊該service worker的頁面需要再次加載才會受其控制。service worker實施控制后,它將處于以下兩種狀態之一:service worker終止以節省內存,或處理獲取和消息事件,從頁面發出網絡請求或消息后將會出現后一種狀態。 以下是service worker初始安裝時的簡化生命周期。 ![](https://box.kancloud.cn/d9f42c7577f6293e1590e7b14a377cc8_702x685.png) <br> ## 先決條件 ### 瀏覽器支持 可用的瀏覽器日益增多。service worker受 Firefox 和 Opera 支持。 Microsoft Edge 現在[表示公開支持](https://developer.microsoft.com/en-us/microsoft-edge/platform/status/serviceworker/)。甚至 Safari 也暗示未來會進行相關開發。 您可以在 Jake Archibald 的 [is Serviceworker ready](https://jakearchibald.github.io/isserviceworkerready/) 網站上查看所有瀏覽器的支持情況。 ### 您需要 HTTPS 在開發過程中,可以通過 localhost 使用service worker,但如果要在網站上部署服務工作線程,需要在服務器上設置 HTTPS。 使用service worker,您可以劫持連接、編撰以及過濾響應。 這是一個很強大的工具。您可能會善意地使用這些功能,但中間人可會將其用于不良目的。 為避免這種情況,可僅在通過 HTTPS 提供的頁面上注冊service worker,如此我們便知道瀏覽器接收的service worker在整個網絡傳輸過程中都沒有被篡改。 Github 頁面 通過 HTTPS 提供,因此這些頁面是托管演示的絕佳位置。 如果想要向服務器添加 HTTPS,您需要獲得 TLS 證書并在服務器上進行設置。 具體因您的設置而異,因此請查看服務器的文檔,并務必查閱 [Mozilla SSL 配置生成器](https://mozilla.github.io/server-side-tls/ssl-config-generator/),了解最佳做法。 <br> ## 注冊service worker 要安裝service worker,您需要通過在頁面中對其進行**注冊**來啟動安裝。 這將告訴瀏覽器service worker JavaScript 文件的位置。 ~~~ if ('serviceWorker' in navigator) { window.addEventListener('load', function() { 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 是否可用,如果可用,則在頁面加載后注冊位于 /sw.js 的服務工作線程。。 每次頁面加載無誤時,即可調用 **register()** 瀏覽器將會判斷 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 是否已啟用。 ![](https://box.kancloud.cn/20d737ae1d6fead86265174a975fc1e6_1358x687.png) 首次執行 service worker 時,您還可以通過 chrome://serviceworker-internals 來查看服務工作線程詳情。 如果只是想了解 service worker 的生命周期,這仍很有用,但是日后其很有可能被 chrome://inspect/#service-workers 完全取代。 您會發現,它還可用于測試隱身窗口中的 service worker ,您可以關閉 service worker 并重新打開,因為之前的 service worker 不會影響新窗口。從隱身窗口創建的任何注冊和緩存在該窗口關閉后均將被清除。 <br> ## Service Worker的安裝步驟 在頁面上完成注冊步驟之后,讓我們把注意力轉到service worker的腳本里來,在這里面,我們要完成它的安裝步驟。 在最基本的例子中,你需要為install事件定義一個callback,并決定哪些文件你想要緩存。 ~~~ self.addEventListener('install', function(event) { // Perform install steps }); ~~~ 在我們的install callback中,我們需要執行以下步驟: 1. 開啟一個緩存 2. 緩存我們的文件 3. 決定是否所有的資源是否要被緩存 ~~~ 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事件。 <br> ## 緩存和返回Request 你已經安裝了service worker,你現在可以返回你緩存的請求了。 當service worker被安裝成功并且用戶瀏覽了另一個頁面或者刷新了當前的頁面,service worker將開始接收到 fetch 事件。下面是一個例子: ~~~ 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` 查找 reques t中被 service worker 緩存命中的 response。 如果我們有一個命中的 response,我們返回被緩存的值,否則我們返回一個實時從網絡請求fetch的結果。這是一個非常簡單的例子,使用所有在 install 步驟下被緩存的資源。 如果我們想要增量地緩存新的請求,我們可以通過處理fetch請求的response并且添加它們到緩存中來實現,例如: ~~~ self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { // 緩存命中 - 返回響應 if (response) { return response; } // 重要:克隆請求。 ? // 請求是一個流,只能被使用一次。 ? // 由于我們通過緩存消耗了一次,而瀏覽器獲取用了一次,我們需要克隆響應。 var fetchRequest = event.request.clone(); return fetch(fetchRequest).then( function(response) { // 檢查是否收到有效的 response if(!response || response.status !== 200 || response.type !== 'basic') { return response; } // 重要提示:克隆響應。 // 響應是一個流,因為我們希望瀏覽器使用響應以及消耗響應的緩存,我們需要克隆它以便我們有兩個流 var responseToCache = response.clone(); caches.open(CACHE_NAME) .then(function(cache) { cache.put(event.request, responseToCache); }); return response; } ); }) ); }); ~~~ 代碼里我們所做事情包括: 1. 添加一個callback到fetch請求的 .then 方法中 1.1. 一旦我們獲得了一個response,我們進行如下的檢查: 1.2. 確保response是有效的 1.3. 檢查response的狀態是否是200 2. 保證response的類型是**basic**,這表示請求本身是同源的,非同源(即跨域)的請求也不能被緩存。 3. 如果我們通過了檢查,clone這個請求。這么做的原因是如果response是一個Stream,那么它的body只能被讀取一次,所以我們得將它克隆出來,一份發給瀏覽器,一份發給緩存。 <br> ## 更新一個Service Worker 你的service worker總有需要更新的那一天。當那一天到來的時候,你需要按照如下步驟來更新: 1. 更新你的service worker的JavaScript文件。當用戶瀏覽你的網站,瀏覽器嘗試在后臺下載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。 下面的代碼能夠循環所有的緩存,刪除掉所有不在白名單中的緩存。 ~~~ 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); } }) ); }) ); }); ~~~ <br> ## 處理邊界和填坑 這一節內容比較新,有很多待定細節。希望這一節很快就不需要講了,但是現在,這些內容還是應該被提一下。 ### 如果安裝失敗了,沒有很優雅的方式獲得通知 如果一個worker被注冊了,但是沒有出現在 chrome://inspect/#service-workers 或 chrome://serviceworker-internals ,那么很可能因為異常而安裝失敗了,或者是產生了一個被拒絕的的 promise 給 `event.waitUtil`。 要解決這類問題,首先到 chrome://serviceworker-internals檢查。打開開發者工具窗口準備調試,然后在你的install event代碼中添加debugger;語句。這樣,通過斷點調試你更容易找到問題。 ### fetch()的默認參數 **默認情況下沒有憑據** 當你使用fetch,缺省地,請求不會帶上cookies等憑據,要想帶上的話,需要: ~~~ fetch(url, { credentials: 'include' }) ~~~ 這樣設計是有理由的,它比XHR的在同源下默認發送憑據,但跨域時丟棄憑據的規則要來得好。fetch的行為更像其他的CORS請求,例如 `<img crossorigin>` ,它默認不發送 cookies,除非你指定了`<img crossorigin="use-credentials">.`。 ### Non-CORS默認不支持 默認情況下,從第三方URL跨域得到一個資源將會失敗,除非對方支持了CORS。你可以添加一個non-CORS選項到Request去避免失敗。代價是這么做會返回一個“不透明”的response,意味著你不能得知這個請求究竟是成功了還是失敗了。 ~~~ cache.addAll(urlsToPrefetch.map(function(urlToPrefetch) { return new Request(urlToPrefetch, { mode: 'no-cors' }); })).then(function() { console.log('All resources have been fetched and cached.'); }); ~~~ ### 處理響應式圖片 `img` 的 `srcset` 屬性或者`<picture>`標簽會根據情況從瀏覽器或者網絡上選擇最合適尺寸的圖片。 在service worker中,你想要在install步驟緩存一個圖片,你有以下幾種選擇: * 安裝所有的`<picture>`元素或者將被請求的srcset屬性。 * 安裝單一的low-res版本圖片 * 安裝單一的high-res版本圖片 比較好的方案是2或3,因為如果把所有的圖片都給下載下來存著有點浪費內存。 假設你將low-res版本在install的時候緩存了,然后在頁面加載的時候你想要嘗試從網絡上下載high-res的版本,但是如果high-res版本下載失敗的話,就依然用low-res版本。這個想法很好也值得去做,但是有一個問題: | Screen Density | Width | Height | |---|---|---| | 1x | 400 | 400 | | 2x | 800 | 800 | 在srcset圖像中,我們有一些像這樣的標記: ~~~ <img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" /> ~~~ 如果我們在一個2x的顯示模式下,瀏覽器會下載image-2x.png,如果我們離線,你可以讀取之前緩存并返回image-src.png替代,如果之前它已經被緩存過。盡管如此,由于現在的模式是2x,瀏覽器會把400X400的圖片顯示成200X200,要避免這個問題就要在圖片的樣式上設置寬高。 ~~~ <img src="image-src.png" srcset="image-src.png 1x, image-2x.png 2x" style="width:400px; height: 400px;" /> ~~~ `<picture>`標簽情況更復雜一些,難度取決于你是如何創建和使用的,但是可以通過與srcset類似的思路去解決。 ## 參考資料 [Service Worker入門](http://web.jobbole.com/82247/) [Service Workers: an Introduction](https://developers.google.com/web/fundamentals/primers/service-workers/)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看