国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

構(gòu)建 Web 應(yīng)用之 Service Worker 初探

voidking / 2963人閱讀

摘要:誕生之初,是單線程的。當(dāng)接收到服務(wù)端的響應(yīng)之后,便通過(guò)回調(diào)函數(shù)執(zhí)行之后的操作。沖鋒基于事件驅(qū)動(dòng)。擁有攔截請(qǐng)求消息推送靜默更新地理圍欄等服務(wù)。控制時(shí)處于兩種狀態(tài)之一終止以節(jié)省內(nèi)存監(jiān)聽(tīng)獲取和消息事件。支持的所有事件五銷(xiāo)毀瀏覽器決定是否銷(xiāo)毀。

這次體驗(yàn)一種新的博客風(fēng)格,我們長(zhǎng)話短說(shuō),針針見(jiàn)“血”。

備馬

在深入 Service Worker 之前,我們需要快速回顧如下基礎(chǔ)。

誕生之初,JavaScript 是單線程的。

進(jìn)程有私有的虛擬地址空間、代碼、數(shù)據(jù)和其它系統(tǒng)資源,進(jìn)程申請(qǐng)創(chuàng)建和使用的系統(tǒng)資源會(huì)隨其終止而銷(xiāo)毀。線程運(yùn)行在進(jìn)程之中,系統(tǒng)創(chuàng)建進(jìn)程之后就開(kāi)始啟動(dòng)執(zhí)行進(jìn)程的主線程,并隨主線程的退出而終止。

JavaScript 作為瀏覽器腳本語(yǔ)言,為方便準(zhǔn)確無(wú)誤的操作 DOM,誕生之初便采用了單線程的方式。舉個(gè)例子,若多線程同時(shí)分別刪除和修改同一個(gè) DOM,我們很難預(yù)知其執(zhí)行結(jié)果。

但單線程中,必須通過(guò)異步和回調(diào)來(lái)優(yōu)化耗時(shí)操作。

我們?cè)诰W(wǎng)頁(yè)上提交一個(gè)表單,并不希望在提交后頁(yè)面卡頓,一直等待服務(wù)端返回的提交結(jié)果。這時(shí)我們需要能在單線程中發(fā)送異步請(qǐng)求,點(diǎn)擊提交表單后可以先在頁(yè)面進(jìn)行其他操作。

Ajax 讓我們可以向后端發(fā)送異步請(qǐng)求,同時(shí)不影響用戶在界面中繼續(xù)操作。當(dāng) Ajax 接收到服務(wù)端的響應(yīng)之后,便通過(guò)回調(diào)函數(shù)執(zhí)行之后的操作。一個(gè)典型的異步 Ajax 實(shí)戰(zhàn)場(chǎng)景如下:

// 生成可發(fā)送同步/異步請(qǐng)求的 XMLHttpRequest 對(duì)象實(shí)例
var oReq = new XMLHttpRequest();
// open 方法初始化請(qǐng)求方法、地址,第三個(gè)參數(shù) true 聲明進(jìn)行異步請(qǐng)求
oReq.open("GET", "http://www.jianshu.com/", true);
// 請(qǐng)求的整個(gè)過(guò)程中有五種狀態(tài),且同一時(shí)刻只能存在一種狀態(tài):
// 1. 未打開(kāi)
// 2. 未發(fā)送
// 3. 已獲取響應(yīng)體
// 4. 正在下載響應(yīng)體
// 5. 請(qǐng)求完成
// 當(dāng)請(qǐng)求狀態(tài)發(fā)生改變時(shí),觸發(fā) onreadystatechange 會(huì)被調(diào)用
oReq.onreadystatechange = function (oEvent) {
  // 如果已經(jīng)開(kāi)始下載響應(yīng)體了
  if (oReq.readyState === 4) {
    // 如果響應(yīng)體成功下載,并且服務(wù)端返回 200 狀態(tài)碼
    if (oReq.status === 200) {
      // 打印響應(yīng)信息
      console.log(oReq.responseText);
    } else {
      console.log("Error", oReq.statusText);
    }
  }
};
// send 方法發(fā)送請(qǐng)求,由于此請(qǐng)求是異步的,該方法立刻返回
oReq.send(null);

當(dāng)我們的多個(gè)請(qǐng)求需要依賴于上一個(gè)請(qǐng)求的服務(wù)端響應(yīng)時(shí),回調(diào)函數(shù)中 Ajax 的層級(jí)逐步提高,可維護(hù)性極度下降,這就是回調(diào)地獄。

I Promise U that I`ll Marry U!!!

Promise 由 ES6 標(biāo)準(zhǔn)原生支持。正如題名,Promise 作出諾言,也要因此承擔(dān)成功(fulfilled)或失敗(rejected)的結(jié)果,以便解決回調(diào)地獄問(wèn)題:

// 生成一個(gè) Promise 實(shí)例,傳入有特定的兩個(gè)參數(shù)的匿名函數(shù)
// Promise 初始狀態(tài)是 pending
// resolve 被調(diào)用時(shí),將 Promise 狀態(tài)改為成功(fulfilled)
// reject 被調(diào)用時(shí),將 Promise 狀態(tài)改為失敗(rejected)
// 該匿名函數(shù)拋出錯(cuò)誤時(shí),Promise 狀態(tài)為失敗(rejected)
var a = new Promise(function(resolve, reject) {
  // setTimeout() 模擬異步請(qǐng)求,成功后執(zhí)行 resolve() 方法
  setTimeout(function() {
      resolve("1")
  }, 2000)
})

a.then(function(val){
    // then() 有兩個(gè)函數(shù)作為參數(shù),onfulfilled 和 onrejected
    // 當(dāng) Promise 狀態(tài)為 fulfilled 時(shí),調(diào)用 then 的 onfulfilled 方法
    // 當(dāng) Promise 狀態(tài)為 rejected 時(shí),調(diào)用 then 的 onrejected 方法
    console.log(val)
    // then() 方法返回 Promise 對(duì)象實(shí)例,所以可被鏈?zhǔn)秸{(diào)用
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
          resolve("2")
      }, 2000)
    })
  })
  .then(function(val) {
    // 鏈?zhǔn)秸{(diào)用的第二個(gè)環(huán)節(jié),處理上一個(gè)環(huán)節(jié)返回的 Promise 對(duì)象
    console.log(val)
  })

Promise 對(duì)象的生命周期如下圖。

除了異步編程,我們還可以有 Web Worker。

通過(guò)異步編程,我們的頁(yè)面可以邊響應(yīng)用戶的下一步操作邊等待服務(wù)端的回應(yīng),不再擁有阻塞感,但 JavaScript 的單線程問(wèn)題并沒(méi)有得到相應(yīng)的解決。通過(guò) HTML 5 標(biāo)準(zhǔn)支持的 Web Worker,我們可以為 JavaScript 創(chuàng)建運(yùn)行在后臺(tái)的額外線程,并被多個(gè)頁(yè)面共享。

在一個(gè)簡(jiǎn)單的 Web Worker 實(shí)例中,main.js 和 task.js 的源碼如下。

// main.js
// 實(shí)例化 Worker 對(duì)象,其實(shí)質(zhì)為新創(chuàng)建的工作線程在主線程的引用
var worker = new Worker("task.js")
// postMessage 方法與新創(chuàng)建的工作線程通信
worker.postMessage({
        id:1,
        msg:"Hello World"
});
// 當(dāng) Worker 線程返回?cái)?shù)據(jù)時(shí),onmessage 回調(diào)函數(shù)執(zhí)行
worker.onmessage = function(message) {
    var data = message.data;
    console.log(JSON.stringify(data))
    // terminate 方法終止 worker 線程的運(yùn)行
    worker.terminate()
};
// 當(dāng) Worker 線程出錯(cuò)時(shí),onerror 回調(diào)函數(shù)執(zhí)行
// error 參數(shù)中封裝了錯(cuò)誤對(duì)象的文件名、出錯(cuò)行號(hào)和具體錯(cuò)誤信息
worker.onerror = function(error) {
    console.log(error.filename, error.lineno, error.message)
}
// task.js
onmessage = function(message) {
    var data = message.data
    data.msg = "Hi from task.js"
    postMessage(data)
}

在 Chrome 瀏覽器里,以上代碼必須運(yùn)行在 Web 容器如 Apache 中。同時(shí),WebKit 內(nèi)核加載并執(zhí)行 Worker 線程的流程如下圖所示。

上述知識(shí)點(diǎn)的詳盡博客盡請(qǐng)期待,您可以先查閱其它資料進(jìn)行補(bǔ)充。
沖鋒

Service Worker 基于 Web Worker 事件驅(qū)動(dòng)。

Service Worker 同樣可以在瀏覽器后臺(tái)掛起新線程,來(lái)緩解 JavaScript 的單線程問(wèn)題。并且,我們可以用 Service Worker 攔截網(wǎng)絡(luò)請(qǐng)求進(jìn)行本地緩存或請(qǐng)求轉(zhuǎn)發(fā),相當(dāng)于充當(dāng)服務(wù)端與瀏覽器、瀏覽器與 Web 應(yīng)用程序之間的代理服務(wù)器。

Service Worker 帶來(lái)了速度,極大的提高了用戶體驗(yàn)。

Service Worker 可有效加快重復(fù)訪問(wèn)網(wǎng)絡(luò)應(yīng)用的速度。

擁有攔截請(qǐng)求、消息推送、靜默更新、地理圍欄等服務(wù)。

可以在客戶端通過(guò) indexedDB API 保存持久化信息。

Service Worker 大量使用 Promise 對(duì)象。

因?yàn)橥ǔ?Service Worker 會(huì)等待響應(yīng)后繼續(xù),并根據(jù)響應(yīng)返回一個(gè)成功或者失敗的操作。Promise 非常適合這種場(chǎng)景。

零、Service Worker 的生命周期。

所謂生命周期,包括 Service Worker 的注冊(cè)、安裝、激活、控制和銷(xiāo)毀時(shí)的全部過(guò)程。我們需要對(duì) Service Worker 的生命周期有所了解。

先決條件:

瀏覽器支持:Service Worker。

在 localhost 域或 HTTPS 域下運(yùn)行:介于我們能夠通過(guò)使用 Service Worker 劫持連接、編撰以及過(guò)濾響應(yīng)來(lái)進(jìn)行權(quán)限較高的操作。

注冊(cè):注冊(cè)過(guò)程獨(dú)立于網(wǎng)頁(yè),先在頁(yè)面執(zhí)行注冊(cè),之后在瀏覽器后臺(tái)啟動(dòng)安裝步驟。

安裝:通常需要緩存某些靜態(tài)資源。當(dāng)所有文件已成功緩存,則安裝完畢。如果任何文件下載失敗或緩存失敗,則安裝失敗,無(wú)法激活。

激活:管理就緩存的絕佳機(jī)會(huì)。激活后它將會(huì)對(duì)作用域頁(yè)面實(shí)時(shí)控制,不過(guò)首次注冊(cè)該服務(wù)工作線程的頁(yè)面需要再次加載才會(huì)受其控制。

控制時(shí):處于兩種狀態(tài)之一:

①、終止以節(jié)省內(nèi)存;

②、監(jiān)聽(tīng)獲取 fetch 和消息 message 事件。

銷(xiāo)毀:由瀏覽器決定,因此盡量不要留存全局變量。

一、注冊(cè) Service Worker。

當(dāng)瀏覽器對(duì) Service Worker 提供原生支持時(shí),我們便可以在頁(yè)面加載后注冊(cè)指定的 JavaScript 文件,并運(yùn)行在后臺(tái)線程之中,以下代碼是這一過(guò)程的實(shí)例。




  ServiceWorker


  

Hello World!

這里通過(guò) php 內(nèi)置命令監(jiān)聽(tīng)項(xiàng)目目錄,便能看到 Service Worker 注冊(cè)成功。同時(shí),在 Chrome 瀏覽器里,可以訪問(wèn) chrome://inspect/#service-workerschrome://serviceworker-internals/ 來(lái)檢查 Service Worker 是否已經(jīng)啟用。

二、安裝 Service Worker。

安裝階段,我們可以執(zhí)行任何任務(wù)。這里我們逐步打開(kāi)緩存、緩存文件和確認(rèn)所有需要的資產(chǎn)是否緩存。ServiceWorker.js 中的實(shí)例安裝代碼如下:

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);
      })
  );
});

這要求我們?cè)谂c項(xiàng)目根目錄下建立 main.jsmain.css 空文件。我們可以在 Chrome 開(kāi)發(fā)者工具里的“Application”菜單的“Cache Storage”中看到相應(yīng)的緩存。并且在圖中的“Service Workers”選項(xiàng)卡中看到正在運(yùn)行的 Service Workers。

且從上面的代碼可以看到,通過(guò) Service Worker 對(duì)象加載的文件擁有全局變量 caches 等,并且 self 關(guān)鍵字指向這個(gè)對(duì)象本身。cache 使我們可以存儲(chǔ)網(wǎng)絡(luò)響應(yīng)發(fā)來(lái)的資源,并且根據(jù)它們的請(qǐng)求來(lái)生成 key。這個(gè) API 和瀏覽器的標(biāo)準(zhǔn)的緩存工作原理很相似,且會(huì)持久存在,直到我們釋放主動(dòng)空間——我們擁有全部的控制權(quán)。

三、激活 Service Worker。

當(dāng) Service Worker 安裝成功后,便被激活,這時(shí)可實(shí)時(shí)控制作用域中的所有網(wǎng)站,進(jìn)行緩存文件等操作。不過(guò)首次使用 Service Worker 的頁(yè)面需要再次加載才會(huì)受其控制。

四、控制 Service Worker

以下列舉幾個(gè)常見(jiàn)的 Service Worker 應(yīng)用場(chǎng)景。

1. 文件緩存

self.addEventListener("fetch", function(event) {
  event.respondWith(
      // 以下方法檢視請(qǐng)求,并從服務(wù)工作線程所創(chuàng)建的任何緩存中查找緩存的結(jié)果。
    caches.match(event.request)
      .then(function(response) {
          console.log(event.request)
          console.log(caches)
        // 如果發(fā)現(xiàn)匹配的響應(yīng),則返回緩存的值
        if (response) {
          return response;
        }
        return fetch(event.request);
      }
    )
  );
});

通過(guò)上述文件緩存過(guò)程,我們可以告訴 Service Worker 如何使用這些緩存文件,并通過(guò) fetch 事件來(lái)捕獲。fetch 事件只會(huì)在瀏覽器準(zhǔn)備請(qǐng)求 Service Worker 控制的資源時(shí)才會(huì)被觸發(fā)。這些資源包括了指定的 scope 內(nèi)的文檔,和這些文檔內(nèi)引用的其他任何資源。

2. 多頁(yè)面?zhèn)鬟f消息

我們可以打開(kāi)多個(gè) https://nzv3tos3n.qnssl.com/m... 測(cè)試頁(yè)面來(lái)進(jìn)行測(cè)試,效果如下。

其中,index.js 源碼為:

(function () {
    if (navigator.serviceWorker) {
        // 獲取頁(yè)面 DOM 元素
        var msgIpt = document.getElementById("ipt"),
            showArea = document.getElementById("show"),
            sendBtn = document.getElementById("sendBtn");

        navigator.serviceWorker.register("service-worker3.js");

        navigator.serviceWorker.addEventListener("message", function (event) {
            // 接受數(shù)據(jù),并填充在 DOM 中
            showArea.innerHTML = showArea.innerHTML + ("
  • " + event.data.message + "
  • "); }); sendBtn.addEventListener("click", function () { // 綁定點(diǎn)擊事件,點(diǎn)擊后發(fā)送數(shù)據(jù) navigator.serviceWorker.controller.postMessage(msgIpt.value); msgIpt.value = ""; }); } })();

    3. 更新 Service Worker

    每次用戶導(dǎo)航至使用 Service Worker 的站點(diǎn)時(shí),瀏覽器會(huì)嘗試在后臺(tái)重新下載該腳本文件。這時(shí)新的 Service Worker 將會(huì)在后臺(tái)安裝,并在第二次訪問(wèn)時(shí)獲取控制權(quán),為了不與新的 Service Worker 緩存的文件沖突,我們可以使用類似 caches.open("v2") 語(yǔ)句來(lái)創(chuàng)建新的緩存目錄。

    this.addEventListener("install", function(event) {
      event.waitUntil(
        // 創(chuàng)建新的緩存目錄,并指定
        caches.open("v2").then(function(cache) {
          return cache.addAll([
            "/sw-test/",
            "/sw-test/index.html",
            …
          ]);
        });
      );
    });

    當(dāng)新的 Service Worker 激活,記得刪除 v1 緩存目錄,代碼如下。

    this.addEventListener("activate", function(event) {
      // 聲明緩存白名單,該名單內(nèi)的緩存目錄不會(huì)被生成
      var cacheWhitelist = ["v2"];
      event.waitUntil(
        // 傳給 waitUntil() 的 promise 會(huì)阻塞其他的事件,直到它完成
        // 確保清理操作會(huì)在第一次 fetch 事件之前完成
        caches.keys().then(function(keyList) {
          return Promise.all(keyList.map(function(key) {
            if (cacheWhitelist.indexOf(key) === -1) {
              return caches.delete(key);
            }
          }));
        })
      );
    });

    4. 預(yù)緩存

    Service Worker 也可以在后臺(tái)主動(dòng)發(fā)送請(qǐng)求,優(yōu)化用戶體驗(yàn),圖片來(lái)源于《餓了么的 PWA 升級(jí)實(shí)踐》。

    5. Service Worker 支持的所有事件

    五、銷(xiāo)毀 Service Worker

    瀏覽器決定是否銷(xiāo)毀 Service Worker。在無(wú)痕瀏覽中,當(dāng)頁(yè)面關(guān)閉時(shí)相應(yīng)的 Service Worker 會(huì)被銷(xiāo)毀,因此盡量不要在代碼中留存全局變量。可以訪問(wèn) chrome://inspect/#service-workers和 chrome://serviceworker-internals/ 來(lái)檢查 Service Worker 是否已經(jīng)停用。

    小結(jié)

    困擾 Web 用戶多年的難題——丟失網(wǎng)絡(luò)連接,從 APPCache 到 Service Worker,解決辦法一直在完善。Service Worker 開(kāi)啟的服務(wù)工作線程,對(duì)如何步入 Web 應(yīng)用開(kāi)發(fā)之旅,提供了很棒的切入角度。

    那么,如何從本文開(kāi)始,更好的學(xué)習(xí) Service Worker?結(jié)合更多其它技術(shù)博客與 Service Worker 的 API 文檔會(huì)更好。本文圖片素材、寫(xiě)作思路多取源于此。

    接口列表
    Cache CacheStorage
    Client Clients
    ExtendableEvent FetchEvent
    InstallEvent Navigator.serviceWorker
    NotificationEvent PeriodicSyncEvent
    PeriodicSyncManager PeriodicSyncRegistration
    ServiceWorker ServiceWorkerContainer
    ServiceWorkerGlobalScope ServiceWorkerRegistration
    SyncEvent SyncManager
    SyncRegistration WindowClient
    相關(guān)代碼

    本文所有關(guān)于 Web Worker、Service Worker 的代碼,持續(xù)更新在我的 gist 中:

    https://gist.github.com/hyler...

    Hello,我是韓亦樂(lè),現(xiàn)任本科軟工男一枚。軟件工程專業(yè)的一路學(xué)習(xí)中,我有很多感悟,也享受持續(xù)分享的過(guò)程。如果想了解更多或能及時(shí)收到我的最新文章,歡迎訂閱我的個(gè)人微信號(hào):韓亦樂(lè)。我的簡(jiǎn)書(shū)個(gè)人主頁(yè)中,有我的訂閱號(hào)二維碼和 Github 主頁(yè)地址;[我的知乎主頁(yè)]中也會(huì)堅(jiān)持產(chǎn)出,歡迎關(guān)注。

    本文內(nèi)部編號(hào)經(jīng)由我的 Github 相關(guān)倉(cāng)庫(kù)統(tǒng)一管理;本文可能發(fā)布在多個(gè)平臺(tái)但僅在上述倉(cāng)庫(kù)中長(zhǎng)期維護(hù);本文同時(shí)采用【知識(shí)共享署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際許可協(xié)議】進(jìn)行許可。

    文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/88793.html

    相關(guān)文章

    • PWA初探整理

      摘要:站點(diǎn)在同一瀏覽器中被訪問(wèn)至少兩次,兩次訪問(wèn)間隔至少為分鐘。詢問(wèn)授權(quán)發(fā)送給后端存儲(chǔ)服務(wù)端向發(fā)送消息,同時(shí)帶上根據(jù)再下發(fā)給對(duì)應(yīng)的瀏覽器觸發(fā)的事件后續(xù)處理參考使用發(fā)送推送 關(guān)鍵特性 Web App Manifest – 在主屏幕添加app圖標(biāo),定義手機(jī)標(biāo)題欄顏色之類 App Shell – 先顯示APP的主結(jié)構(gòu),再填充主數(shù)據(jù),更快顯示更好體驗(yàn) Service Worker - 緩存,離線開(kāi)...

      jifei 評(píng)論0 收藏0
    • 初探IndexedDB

      背景 隨著前端技術(shù)日新月異地快速發(fā)展,web應(yīng)用功能和體驗(yàn)也逐漸發(fā)展到可以和原生應(yīng)用媲美的程度,前端緩存技術(shù)的應(yīng)用對(duì)這起到了不可磨滅的貢獻(xiàn),因此想一探前端的緩存技術(shù),這篇文章主要會(huì)介紹在日常開(kāi)發(fā)中比較少接觸的IndexedDB IndexedDB 什么是IndexedDB IndexedDB簡(jiǎn)單理解就是前端數(shù)據(jù)庫(kù),提供了一種在用戶瀏覽器中持久存儲(chǔ)數(shù)據(jù)的方法,但是和前端關(guān)系型數(shù)據(jù)不同的是,Index...

      jsyzchen 評(píng)論0 收藏0
    • 前端每周清單半年盤(pán)點(diǎn) PWA 篇

      摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開(kāi)發(fā)教程工程實(shí)踐深度閱讀開(kāi)源項(xiàng)目巔峰人生等欄目。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開(kāi)發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開(kāi)發(fā)教程、工程實(shí)踐、深度閱讀、開(kāi)源項(xiàng)目、巔峰人生等欄目。歡迎關(guān)注【前端之巔】微信公眾號(hào)(ID:frontshow),及時(shí)獲取前端每周清單;本文則是對(duì)于...

      崔曉明 評(píng)論0 收藏0

    發(fā)表評(píng)論

    0條評(píng)論

    最新活動(dòng)
    閱讀需要支付1元查看
    <