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

資訊專欄INFORMATION COLUMN

service worker在移動端H5項目的應(yīng)用

cucumber / 2186人閱讀

摘要:和的關(guān)系不是一項技術(shù),也不是一個框架,我們可以把她理解為一種模式,一種通過應(yīng)用一些技術(shù)將在安全性能和體驗等方面帶來漸進式的提升的一種的模式。這里需要注意的是,首次注冊線程的頁面需要再次加載才會受其控制。

1. PWA和Service Worker的關(guān)系

PWA (Progressive Web Apps) 不是一項技術(shù),也不是一個框架,我們可以把她理解為一種模式,一種通過應(yīng)用一些技術(shù)將 Web App 在安全、性能和體驗等方面帶來漸進式的提升的一種 Web App的模式。對于 webview 來說,Service Worker 是一個獨立于js主線程的一種 Web Worker 線程, 一個獨立于主線程的 Context,但是面向開發(fā)者來說 Service Worker 的形態(tài)其實就是一個需要開發(fā)者自己維護的文件,我們假設(shè)這個文件叫做 sw.js。通過 service worker 我們可以代理 webview 的請求相當于是一個正向代理的線程,fiddler也是干這些事情),在特定路徑注冊 service worker 后,可以攔截并處理該路徑下所有的網(wǎng)絡(luò)請求,進而實現(xiàn)頁面資源的可編程式緩存,在弱網(wǎng)和無網(wǎng)情況下帶來流暢的產(chǎn)品體驗,所以 service worker 可以看做是實現(xiàn)pwa模式的一項技術(shù)實現(xiàn)。

2. service worker簡介

注意事項

service worker 是一種JS工作線程,無法直接訪問DOM, 該線程通過postMessage接口消息形式來與其控制的頁面進行通信;

service worker 廣泛使用了Promise,這些在接下來代碼示例中將會看到;

目前并不是所有主流瀏覽器支持 service worker, 可以通過 navigator && navigator.serviceWorker 來進行特性探測;

在開發(fā)過程中,可以通過 localhost 使用服務(wù)工作線程,如若上線部署,必須要通過https來訪問注冊服務(wù)工作線程的頁面,但有種場景是我們的測試環(huán)境可能并不支持https,這時就要通過更改host文件將localhost指向測試環(huán)境ip來巧妙繞過該問題(例如:192.168.22.144 localhost);

生命周期

service worker的生命周期完全獨立于網(wǎng)頁,要為網(wǎng)站安裝服務(wù)工作線程,我們需要在頁面業(yè)務(wù)js代碼中注冊,瀏覽器從指定路徑下載并解析服務(wù)工作線程腳本進而瀏覽器將會在后臺啟動安裝步驟,在安裝過程中,我們通常會緩存靜態(tài)資源,如果所有文件都成功緩存,那么服務(wù)工程線程就安裝完畢,如果任何文件下載失敗或緩存失敗,那么安裝步驟將會失敗,當然也不會被激活。安裝后就進入激活步驟,這里是管理舊緩存的絕佳機會(后面代碼示例中將會介紹原因),激活后service worker將開始對其作用域內(nèi)的所有頁面實施控制。這里需要注意的是,首次注冊 service worker 線程的頁面需要再次加載才會受其控制。在成功安裝完成并處于激活狀態(tài)之前,服務(wù)工程線程不會收到fetch和push事件;

工作流程

注冊

這里需要注意的是register方法注冊服務(wù)工作線程文件的位置,該path就是默認的 serviceworker 的作用域,例如注冊path為/a/b/service-worker.js,則默認scope為/a/b/,當然也可以通過傳入{scope: "/a/b/c/"}來指定自己的scope,但這里要特別注意的是,傳入的scope參數(shù)一定是在默認作用域范圍內(nèi)再自定義(例如/a/b/c/),反之自定義為/d/e/就不行;

通俗來講,上面提到的scope就是 service worker 能夠控制和發(fā)揮作用的范圍;

注意注冊是在自己的業(yè)務(wù)代碼中進行,后面會有具體通過插件來實現(xiàn)注冊的代碼示例;

if(navigator && navigator.serviceWorker) {
    navigator.serviceWorker.register("/service-worker.js").then(function (registration) {
        console.log(registration)
    }).catch(function (err) {
        console.log(err)
    })
}

安裝

下面代碼就是前面注冊的service-worker.js文件內(nèi)容;

我們通過install事件來定義安裝步驟,通過緩存名稱調(diào)用caches.open(), 之后再調(diào)用cache.addAll()并傳入具體緩存文件清單數(shù)組,這是一個Promise鏈式event.waitUntil()方法帶有Promise參數(shù)并使用它來判斷花費耗時以及安裝是否成功;

正如前面提到,安裝過程中如果所有清單中文件成功緩存,則安裝結(jié)束,否則安裝過程視為失敗,所以在實踐中我們盡可能緩存核心資源以避免服務(wù)工作線程未能安裝;

var cacheVersion = "test_2017122608";
// 安裝服務(wù)工作線程
self.addEventListener("install", function(event){
    // 需要緩存的資源
    var cacheFiles = [
        "/dist/index.html",
        "/dist/js/index_async_bundle.js"
    ];
    console.log("service worker: run into install");
    event.waitUntil(caches.open(cacheVersion).then(function(cache)
    {
        return cache.addAll(cacheFiles);
    }));
});

?激活

在某個時間點服務(wù)工程線程需要更新(例如:service-worker.js文件發(fā)生更改并上線),用戶訪問頁面時瀏覽器會嘗試在后臺重新下載service-worker.js,如果服務(wù)工程線程文件與當前所用文件存在字節(jié)差異,則將其視為“新服務(wù)工作線程”;

新服務(wù)工作線程將會啟動,且將會觸發(fā) install 事件;

此時舊的服務(wù)工作線程仍將控制著當前頁面,因此新服務(wù)工作線程將會進入waiting狀態(tài);

當網(wǎng)站當前頁面關(guān)閉時,舊服務(wù)工作線程將會終止,新服務(wù)工作線程將會取得控權(quán);

新服務(wù)工作線程取得控制權(quán)后,將會觸發(fā) activate 事件;

監(jiān)聽 activate 事件的回調(diào)函數(shù)中常見的任務(wù)是管理緩存,前面我也提到過這是管理舊緩存的絕佳時機,因為如果在安裝步驟中清理了舊緩存,由于舊的服務(wù)工作線程仍舊控制著頁面,將無法從緩存中提取文件,但是在 activate 時舊服務(wù)工作線程已經(jīng)終止了頁面控制權(quán),所在在這里清理舊緩存再合適不過;

// 新的service worker線程被激活(其實和離線包一樣存在"二次生效"的機理)
self.addEventListener("activate", function (event) {
    console.log("service worker: run into activate");
    event.waitUntil(caches.keys().then(function (cacheNames) {
        return Promise.all(cacheNames.map(function (cacheName) {
            // 注意這里cacheVersion也可以是一個數(shù)組
            if(cacheName !== cacheVersion){
                console.log("service worker: clear cache" + cacheName);
                return caches.delete(cacheName);
            }
        }));
    }));
});

監(jiān)聽

這里通過監(jiān)聽fetch事件來代理響應(yīng),進而實現(xiàn)自定義前端資源緩存;

在event.respondWith()中我們傳入來自caches.match()的一個promise,此方法攔截請求并從服務(wù)工作線程所創(chuàng)建的任何緩存中查找緩存結(jié)果,如若發(fā)現(xiàn)匹配的響應(yīng)則返回緩存的值,否則,將會調(diào)用fetch以代理發(fā)出網(wǎng)絡(luò)請求,并將從網(wǎng)絡(luò)中檢索的數(shù)據(jù)作為結(jié)果返回;

如果希望連續(xù)性緩存新的請求,則注意注釋的代碼部分,其通過cache.put來將請求的響應(yīng)添加到緩存來實現(xiàn);

在fetch請求中添加對then()的回調(diào),獲得響應(yīng)后執(zhí)行檢查,并clone響應(yīng),注意這樣處理的原因是該響應(yīng)是stream,主體只能使用一次,我們需要返回能被瀏覽器使用的響應(yīng),還要傳遞到緩存以供使用,因此需要克隆一份副本;

// 攔截請求并響應(yīng)
self.addEventListener("fetch", function (event) {
    console.log("service worker: run into fetch");
    event.respondWith(caches.match(event.request).then(function (response) {
        // 發(fā)現(xiàn)匹配的響應(yīng)緩存
        if(response){
            console.log("service worker 匹配并讀取緩存:" + event.request.url);
            return response;
        }
        console.log("沒有匹配上:" + event.request.url);
        return fetch(event.request);
        /*var fetchRequest = event.request.clone();
        return fetch(fetchRequest).then(function(response){
            if(!response || response.status !== 200 || response.type !== "basic"){
                return response;
            }
            var responseToCache = response.clone();
            caches.open(cacheVersion).then(function (cache) {
                console.log(cache);
                cache.put(fetchRequest, responseToCache);
            });
            return response;
        });*/
    }));
});

3. 前端資源緩存演進

利用webview自身的http緩存機制。這里往往需要服務(wù)器運維同事配合,對于前端來講不夠靈活且緩存粒度太粗,而且在http協(xié)議在不同版本下緩存機制有一定的差異(例如1.0版本中If-Modified-Since、Last-Modified、expires, 1.1版本中對緩存進行了優(yōu)化,添加If-None-Match、Etag、cache-control等;

離線包策略,其大致原理是通過將靜態(tài)資源打包至離線管理平臺(自行開發(fā)),在app啟動時從離線管理平臺拉取資源包并存放于本地,后續(xù)終端將會攔截url請求并基于約定規(guī)則將請求代理到本地文件系統(tǒng),進而加快靜態(tài)資源的訪問以及為cdn減壓,該方案的缺陷在于需要離線資源管理平臺和終端的配合,牽扯資源過多,但其優(yōu)點是不存在兼容性問題;

h5離線緩存manifest,其實質(zhì)就是一個緩存清單文件(xx.manifest),然后在html標簽設(shè)置manifest屬性為xx.manifest,該緩存方案也存在“二次更新”的問題,該方案需要注意的問題是xx.manifest文件自身不要被webview緩存,且manifest文件cache部分不能使用通配符,必須手動指定,不過好在可以通過構(gòu)建工具來解決,主流瀏覽器對該方案支持度也不錯。與service worker相對,其業(yè)務(wù)JS代碼無法感知緩存更新的時機,所以service worker方案更具有想象空間;

service worker 通過一個獨立JS線程來實現(xiàn)資源的可編程式緩存;

4. 項目如何快速接入service worker

在接入前有兩個問題擺在我們面前,service worker可以幫助我們解決資源緩存問題,有緩存就必須要有更新的機制,service-worker.js本身也會被瀏覽器緩存,后續(xù)產(chǎn)品迭代過程中如何解決該文件自身的更新問題,否則其他資源的緩存更新也就無從談起(舊的服務(wù)工作線程將一直控制頁面),無可厚非每次構(gòu)建部署時service-worker.js需要攜帶版本號(例如?v=201801021721),當然也可以在服務(wù)器運維層控制該文件的cache-control: no-cache從而規(guī)避瀏覽器緩存問題,但這樣太麻煩;

我們是在業(yè)務(wù)代碼中通過register的方式引入service-worker.js, 那問題就變?yōu)槿绾卧谧苑?wù)工作線程的位置引入版本號呢,我們可以通過sw-register-webpack-plugin來解決該問題,其思路是將服務(wù)工作線程的注冊放在一個多帶帶的文件中(sw-register.js),然后自動在頁面入口(例如index.html)寫入一段JS腳本來動態(tài)加載sw-register.js文件,這里sw-register.js的加載路徑是帶有實時時間戳的,而生成的sw-register.js文件內(nèi)容中注冊service-worker.js的位置自動攜帶構(gòu)建版本號參數(shù)(默認是當前構(gòu)建時間),該插件配置如下(基于webpack構(gòu)建的項目):

let SwRegisterWebpackPlugin = require("sw-register-webpack-plugin")
...
plugins: [
    new SwRegisterWebpackPlugin({
        filePath: path.resolve(__dirname, "../src/sw-register.js")
    })
]

構(gòu)建后html新增部分如圖:

構(gòu)建后生成的sw-register.js文件變化如圖:

這樣處理后,sw-register.js文件就不會被瀏覽器緩存,也即每次刷新會多一次sw-register.js的文件請求,由于它只是用來做注冊的工作,體量不會太大,可以接受,關(guān)鍵是前端可以自行控制

已緩存資源文件如何更新呢?上述插件只是解決了service-worker.js文件本身的更新的問題(保證每次構(gòu)建部署后會新啟一個服務(wù)工作線程),但對于service-worker.js文件中定義的cacheFiles而言,當我們修改了已緩存文件后如何來更新緩存呢,我的項目是基于vue.js + webpack,打包后的JS文件是[name].[hash].[ext]格式,從前面的介紹可知資源的緩存也是基于url(作為key)來的,不可能每次構(gòu)建后都手動去調(diào)整service-worker.js文件內(nèi)容中cacheFiles的路徑值吧,應(yīng)該是將構(gòu)建后的文件名(包括路徑)直接放到service-worker.js內(nèi)容中,看到這里你應(yīng)該想到了有webpack插件已經(jīng)幫我們做好了,那就是sw-precache-webpack-plugin,該插件會自動在dist目錄下生成service-worker.js文件,供給service worker運行,也就是說service-worker.js文件本身不需要我們手動添加了,但問題是我們?nèi)绾巫远x需要緩存的文件呢,該插件的配置參數(shù)會告訴你,我的項目該插件配置如下:

// 生成service-worker.js和配置緩存清單
new SwPrecacheWebpackPlugin({
    cacheId: "attendance-mobile-cache",
    filename: "service-worker.js",
    minify: true,
    dontCacheBustUrlsMatching: false,
    staticFileGlobs: [
        "dist/static/js/manifest.**.*",
        "dist/static/js/vendor.**.*",
        "dist/static/js/app.**.*"
    ],
    stripPrefix: "dist/"
})

由上可知,我們能夠通過正則來匹配需要緩存的文件,這里特別要注意的是stripPrefix參數(shù)的使用,我們配置的緩存文件路徑是項目中的路徑,但對于部署線上而言,我們可能需要過濾前綴的部分路徑(我的項目線上部署文件根目錄下就是static等,所以需要過濾dist路徑),最終該插件生成的service-worker.js文件如圖所示(僅截取緩存文件清單部分代碼)

4. 調(diào)試service worker

通過上述兩個插件,我們的service-worker接入工作基本完成,那接下來就是驗證服務(wù)工作線程運行是否ok,通過chrome devTools(Application項)我們可以很方面的查看當前服務(wù)工作線程的運行情況和已緩存了哪些文件,具體如何查看這里不再介紹;

當首次運行 service worker 時我們會發(fā)現(xiàn)要緩存的文件還是走正常的網(wǎng)絡(luò)請求,cache storage 下也看不到我們的緩存項,因為服務(wù)工程線程也存在“二次生效”的機制(即使需要緩存的資源延遲加載),具體如下圖所示:


通過刷新訪問我們可以看到,service worker 緩存文件已經(jīng)生效,在network面板下自定義的緩存文件size項都顯示為“from ServiceWorker”, 耗時也明顯很低。在cache storage下面也可以看到已經(jīng)緩存的文件列表,具體如下圖所示:


接下來我們更新service-worker.js文件來看下新服務(wù)工作線程如何工作,正如前面所講新服務(wù)工作線程將會啟動安裝,但由于舊服務(wù)工作線程控制著頁面,所以新服務(wù)工作線程將進入waiting狀態(tài),當當前打開的頁面關(guān)閉時,舊服務(wù)工作線程將會被終止,新服務(wù)工作線程會得的控制權(quán)并觸發(fā)activate事件,在開發(fā)過程中我們需要通過Chrome Devtools的skipWaiting或者勾選Updated on reload來強制激活新服務(wù)工作線程,具體如下圖所示:

在開發(fā)過程中我們可以通過上述來了解新服務(wù)工作線程的更新流程,但在實際項目中我們可以通過self.skipWaiting()跳過等待過程安裝后直接激活,一般我們在install事件中調(diào)用,具體可參見sw-precache-webpack-plugin生成的service-worker源代碼。這會導(dǎo)致新服務(wù)工作線程將當前活動的工作線程逐出,skipWaiting()意味著新服務(wù)工作線程可能會控制使用較舊工作線程加載的頁面,也就是頁面獲取的部分數(shù)據(jù)由舊工作線程處理,而新服務(wù)工作線程處理后來獲取的數(shù)據(jù),如果有問題就不要使用skipWaiting();

手動清理service worker緩存后刷新頁面,在 Network 面板中,我們會看到本應(yīng)緩存文件的一組初始請求。之后是前面帶有齒輪圖標的第二輪請求,這些請求似乎要獲取相同的資源,“齒輪”圖標代表這些請求來自服務(wù)工作線程,如果不unregsiter該服務(wù)工作線程,我們會發(fā)現(xiàn)即使多次刷新頁面,Network 面板依然如此,其實也就是說資源沒有再次緩存(因為服務(wù)工作線程已經(jīng)安裝且控制當前頁面,刷新操作不會重新觸發(fā)install事件,也就不會再次添加資源到緩存,除非unregister或者更新service-worker.js文件),具體如下圖所示:


5. 異常回滾(注銷)

某些場景下如果service worker使用出現(xiàn)異常,比如不同頁面間 service worker 控制的scope存在“重疊污染”的問題,那么我們就需要緊急回滾(撤銷)當前 service worker,在開發(fā)環(huán)境很好解決,我們依然可以通過Chrome Devtools來進行unregister, 那么在線上環(huán)境已經(jīng)有服務(wù)工作線程在運行的情況下呢,我們需要在新上線版本的service worker注冊前將被污染或者異常的service worker注銷掉,具體代碼如下:

if (navigator.serviceWorker) {
    navigator.serviceWorker.getRegistrations().then(function (registrations) {
        for (var item of registrations) {
            if (item.scope === "http://localhost/attendance-mobile/dist/") {
                item.unregister();
            }
        }
        // 注銷掉污染 Service Worker 之后再重新注冊...
    });
}

備注:文中部分內(nèi)容摘選自Google開發(fā)者文檔

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

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

相關(guān)文章

  • service worker移動H5項目應(yīng)用

    摘要:和的關(guān)系不是一項技術(shù),也不是一個框架,我們可以把她理解為一種模式,一種通過應(yīng)用一些技術(shù)將在安全性能和體驗等方面帶來漸進式的提升的一種的模式。這里需要注意的是,首次注冊線程的頁面需要再次加載才會受其控制。 1. PWA和Service Worker的關(guān)系 PWA (Progressive Web Apps) 不是一項技術(shù),也不是一個框架,我們可以把她理解為一種模式,一種通過應(yīng)用一些技...

    Tonny 評論0 收藏0
  • 每周清單半年盤點之 PWA 篇

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

    崔曉明 評論0 收藏0
  • 構(gòu)建離線web應(yīng)用(一)

    摘要:我喜歡移動,而且也是那些堅持使用技術(shù)構(gòu)建移動應(yīng)用程序的人之一。我們準備做這樣的一個漸進式應(yīng)用是典型的旨在提高用戶離線體驗的應(yīng)用。當我們開始構(gòu)建應(yīng)用時,你就能理解上面的場景了。的作用范圍是針對相對路徑的。最佳的做法是在應(yīng)用的入口。 我喜歡移動app,而且也是那些堅持使用Web技術(shù)構(gòu)建移動應(yīng)用程序的人之一。 經(jīng)過技術(shù)的不斷迭代(可能還有一些其它的東西),移動體驗設(shè)計愈來愈平易近人,給予用戶...

    Sanchi 評論0 收藏0
  • 用vue從零開發(fā)和部署一款移動pwa單頁應(yīng)用

    摘要:另外,單頁應(yīng)用因為數(shù)據(jù)前置到了前端,不利于搜索引擎的抓取。所以我們需要對自己的單頁應(yīng)用進行一些優(yōu)化。 前言 最近秋招之余空出時間來按自己的興趣動手做了一個項目,一個基于vue-cli3.0, vue,typescript的移動端pwa,現(xiàn)在趁熱打鐵,將這個項目從開發(fā)到部署整個過程記錄下來,并將從這個項目中學習到的東西分享出來,如果大家有什么意見或補充也可以在評論區(qū)提出。先介紹一下這個項...

    Channe 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<