(第七天)HTML5應(yīng)用程序的緩存與Web Worker&服務(wù)器消息推送

Web文件的緩存(Cache)


manifest 文件的建議的文件擴展名是:".appcache"。
manifest 文件需要配置正確的 MIME-type慨仿,即 "text/cache-manifest"掖棉。必須在 web 服務(wù)器上進行配置勇边。

緩存的作用

通過對網(wǎng)頁文件的緩存醋界,達到離線瀏覽的目的

緩存的好處
  • 離線瀏覽 - <small>用戶可在應(yīng)用離線時使用它們</small>
  • 優(yōu)化訪問速度 - <small>已緩存資源加載得更快</small>
  • 降低服務(wù)器負載 - <small>瀏覽器將只從服務(wù)器下載更新過或更改過的資源逢渔。</small>
如何實現(xiàn)緩存功能热凹?
  1. 創(chuàng)建manifest文件(如web.appcache)赐俗,并根據(jù)manifest文件的結(jié)構(gòu)書寫緩存指令
  • manifest文件的結(jié)構(gòu)
    • 第一部分:CACHE MANIFEST - <small>在此標題下列出的文件將在首次訪問后進行緩存</small>
    • 第二部分:NETWORK - <small>在此標題下列出的文件需要與服務(wù)器的連接宽闲,且不會被緩存</small>
    • 第三部分:FALLBACK - <small>在此標題下列出的文件規(guī)定當(dāng)頁面無法訪問時的回退頁面(比如 404 頁面)</small>
    • #開頭的是注釋行众眨,可寫在任何部分中,方便注釋及更新緩存使用
  • mainfest文件相關(guān)注意點
    • CACHE MANIFEST字符的起始點必須位于文件的第一個字符處容诬,否則文件無法解析娩梨,導(dǎo)致緩存無法實現(xiàn);即使有個空格都不行览徒。NETWORKFALLBACK的書寫順序沒有強制要求狈定。
    • manifest文件內(nèi)容一旦被改動,瀏覽器會根據(jù)最新的manifest文件規(guī)則更新進行緩存习蓬。
    • 若web文件同時在CACHE MANIFESTNETWORK標題下出現(xiàn)纽什,瀏覽器會將文件進行緩存處理,即CACHE MANIFEST優(yōu)先級比NETWORK
    • 緩存的文件來源兩個地方:一是CACHE MANIFEST標題下的文件躲叼,二是FALLBACK中無法訪問時的回退頁面(如404頁面)
    • 若manifest屬性被定義芦缰,那么需要訪問網(wǎng)絡(luò)的所有文件都需要寫在NETWORK標題下。因此NETWORK標題下的內(nèi)容常用*通配符表示
  1. <html>標簽上添加manifest屬性枫慷,并指定manifest文件的路徑 <html manifest="web.appcache">让蕾,瀏覽器會根據(jù)manifest文件中的指令進行緩存處理。
HTML代碼示例
<!DOCTYPE html>
<!--定義manifest屬性或听,并指定文件路徑-->
<html lang="en" manifest="index.appcache">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="style.css" type="text/css">
    <script src="index.js"></script>
</head>

<body>
<header>
    <img src="logo.gif" alt="">
</header>
</body>

</html>
manifest文件內(nèi)容示例
CACHE MANIFEST
# 2016-10-23 v1.0.3
# 以下文件會被緩存
/index.js
/logo.gif

# 所有文件都需要訪問網(wǎng)絡(luò)
# 若style.css不可訪問網(wǎng)絡(luò)探孝,也沒有緩存,
# 那么將無法訪問到style.css文件神帅,即網(wǎng)頁無法加載style.css
NETWORK:
* 

FALLBACK:
#/sub文件,404.html會被緩存
/sub    404.html
#/sub/目錄下的所有文件
/sub/   404.html
如何更新緩存 <small>修改manifest文件內(nèi)容</small>
  • 添加刪除或修改manifest緩存文件萌抵;
  • 更新manifest文件中的注釋信息找御,如版本信息;常用于文件不變但需要瀏覽器重新下載緩存文件的時候绍填,如css文件霎桅、js文件更新。

注:瀏覽器對緩存數(shù)據(jù)的容量限制可能不太一樣(某些瀏覽器設(shè)置的限制是每個站點 5MB)讨永。

Web Worker


大部分瀏覽器都支持Worker滔驶,但IE瀏覽器不支持;判斷是否支持的方法:if(Worker){...}else{不支持};

什么是 Web Worker卿闹?

web worker 是運行在后臺的 JavaScript揭糕,獨立于其他腳本萝快,不會影響頁面的性能。您可以繼續(xù)做任何愿意做的事情:點擊著角、選取內(nèi)容等等揪漩,而此時 web worker 在后臺運行。

在 HTML 頁面中執(zhí)行腳本時吏口,頁面的狀態(tài)是不可響應(yīng)的奄容,直到腳本已完成。

什么時候使用Web Worker产徊?

當(dāng)需要js處理復(fù)雜度較高的事務(wù)時昂勒,為了避免影響交互頁面的用戶體驗,可通過Worker后臺處理相關(guān)事務(wù)舟铜,處理好之后返回前臺簡單處理即可戈盈。

Web Worker的使用方法
  • 創(chuàng)建Worker var w = new Worker("worker.js")
  • 設(shè)置Worker的消息監(jiān)聽事件w.onmessage = function(ev){...},當(dāng)Worker(即worker.js)傳回消息時執(zhí)行函數(shù)(得到回傳數(shù)據(jù)后做前臺處理即可)
  • 發(fā)送數(shù)據(jù)給Worker(即worker.js)處理w.postMessage(...)
  • Worker(即worker.js)設(shè)置消息監(jiān)聽事件this.onmessage = function(ev){...} 深滚,當(dāng)Worker(即worker.js)收到w發(fā)送的消息后奕谭,執(zhí)行函數(shù)
  • 當(dāng)Worker(即worker.js)處理完成之后將數(shù)據(jù)發(fā)送給w即可,this.postMessage(...)
  • 觸發(fā)第二步的消息監(jiān)聽事件

worker.js就是一個Worker實例的文件痴荐,復(fù)雜的事務(wù)就在該js中處理血柳,處理完成后回傳給HTML頁面。
worker通過postMessage(...)方法發(fā)送消息生兆,通過onmessage事件監(jiān)聽接收消息难捌,消息的內(nèi)容通過ev.data獲取

如何終止Worker

通過w.terminate()方法即可終止Worker,并釋放其瀏覽器/計算機資源

Worker相關(guān)注意點
  • Worker只能在服務(wù)端運行鸦难;因此需要看Worker效果的話需要搭建Web Server
  • 由于 web worker 位于外部文件中根吁,所以無法訪問下例 JavaScript 對象:
    • window對象
    • document對象
    • parent對象
代碼示例
  • HTML代碼
<body>
    <form>
        <label for="first">first:</label>
        <input type="number" id="first">
        <label for="second">second</label>
        <input type="number" id="second">
        <output class="result"></output>
    </form>
    <script src="index.js"></script>
</body>
  • index.js代碼
"use strict";
var first, second, result, w;
// querySelectorAll(".result") 獲取指定CSS選擇器的所有元素 
// querySelector 獲取指定CSS選擇器的第一個元素
first = document.querySelector("#first");
second = document.querySelector("#second");
result = document.querySelector(".result");
console.log(w + first.value + "<br/>" + second.value + "<br/>" + result.textContent);
// 判斷瀏覽器是否支持Worker,也可通過typeof(Worker) === "undefined"合蔽;這里的window表示self=this击敌,故可以不寫
if (window.Worker) {
  console.log(typeof(w));
  // typeof() 判斷對象類型;如果w為undefined類型拴事,即未定義沃斤,則創(chuàng)建一個Worker對象
  if (typeof(w) === "undefined") {
      w = new Worker("plus.js");
  }
  // second元素的change事件監(jiān)聽
  first.onchange = postMsg;
  // second元素的change事件監(jiān)聽
  second.onchange = postMsg;
  // worker的message事件監(jiān)聽
  w.onmessage = function(ev) {
      result.textContent = ev.data;
  };
} else {
  result.textContent = "您的瀏覽器不支持Worker";
}
// 監(jiān)聽到change事件執(zhí)行的發(fā)送信息函數(shù)
function postMsg() {
  // 判斷first數(shù)據(jù)不為NaN
  if (isNaN(first.valueAsNumber)) {
      first.valueAsNumber = 0;
  }
  if (isNaN(second.valueAsNumber)) {
      second.valueAsNumber = 0;
  }
  // 將兩個值封裝為數(shù)組發(fā)送給plus.js這個worker對象
  w.postMessage([first.valueAsNumber, second.valueAsNumber]);
}
  • plus.js代碼
// plus.js是一個Worker對象,這里的this可以不寫
this.onmessage = function(ev) {
  // 將傳遞過來的first和second相加后發(fā)送給該worker對象,即index.js中的w
  var result = "result:" + (ev.data[0] + ev.data[1]);
  postMessage(result);
}
上述代碼示例效果圖

服務(wù)器消息推送EventSource


服務(wù)器消息推送的實現(xiàn)方法
  • WebSocket:功能強大刃宵,但實現(xiàn)起來技術(shù)比較復(fù)雜
  • HTTP協(xié)議的簡易輪詢:弊端無法很好解決
    • 輪詢周期過程過長衡瓶,客戶端更新數(shù)據(jù)不及時
    • 輪詢周期過程過短,增加服務(wù)端的負擔(dān)
  • EventSource:通過客戶端實時監(jiān)聽服務(wù)端的推送情況牲证,缺點是IE瀏覽器不支持哮针。
EventSource如何使用?
  • 在服務(wù)端推送消息頁面添加一個內(nèi)容為'Content-Type: text/event-stream'的header
  • 在HTML頁面JS中創(chuàng)建EventSource對象 var es = new EventSource("postmsg.php");<small>注:postmsg.php為服務(wù)端推送消息頁面的訪問路徑</small>
  • 為EventSource實例添加事件監(jiān)聽
    • es.onopen = function(ev){...}:與服務(wù)器建立連接后觸發(fā)的事件
    • es.onerror = function(ev){...}:發(fā)生錯誤時觸發(fā)的事件,錯誤包含很多種十厢,網(wǎng)絡(luò)連接錯誤等太,編碼錯誤等等
    • es.onmessage = function(ev){...}:接收到服務(wù)器端推送消息的事件;獲取消息的方法ev.data
  • 服務(wù)端發(fā)送消息寿烟,消息的格式為data:消息內(nèi)容
代碼示例
  • php服務(wù)端
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$time = date('Y-m-d H:m:s');
echo "data: {$time}\n\n"; //這里\n\n必須加澈驼,否則消息無法被獲取
flush();
?>
  • HTML頁面
<head>
    <script>
    "use strict";
    var serverStatus, serverDate, eventSource;
    window.onload = function(ev) {
        serverStatus = document.getElementById("serverStatus");
        serverDate = document.getElementById("serverDate");
        // 判斷瀏覽器是否支持EventSource,IE不支持筛武,其他瀏覽器都支持
        if (typeof(EventSource) !== "undefined") {
            startServSendLinstener();
        } else {
            document.body.innerHTML = "Sorry! No server-sent events support..";
        }
    };
    //運行服務(wù)器端推送消息的事件服務(wù)
    function startServSendLinstener() {
        serverStatus.innerHTML = "Server is Connecting...";
        eventSource = new EventSource("test.php");
        // console輸出eventSource調(diào)用的URL缝其,即test.php是URL
        console.log(eventSource.url);
        /*EventSource對象中的三個監(jiān)聽事件*/
        // 與服務(wù)器建立連接后觸發(fā)的事件
        eventSource.onopen = openHandler;
        // 發(fā)生錯誤時觸發(fā)的事件
        eventSource.onerror = errorHandler;
        // 接收數(shù)據(jù)時觸發(fā)的事件;事件中的data負責(zé)傳輸服務(wù)器端發(fā)送的數(shù)據(jù)
        // eventSource.onmessage = msgHandler;

        // 添加EventSource的message事件監(jiān)聽徘六,效果與eventSource.onmessage一樣内边;
        eventSource.addEventListener("message", msgHandler);
    }

    // 與服務(wù)器連接完成后執(zhí)行的函數(shù)
    function openHandler(ev) {
        // 更新頁面中的serverStatus
        serverStatus.innerHTML = "Connect Success!"
    }

    // 出現(xiàn)錯誤執(zhí)行的函數(shù),錯誤包含很多種待锈,網(wǎng)絡(luò)連接錯誤漠其,編碼錯誤等等
    function errorHandler(ev) {
        // 更新頁面中的serverStatus
        console.log(ev);
        serverStatus.innerHTML = "errors";
    }

    // 獲取服務(wù)端信息后執(zhí)行的函數(shù)
    function msgHandler(ev) {
        // 更新頁面中的serverDate
        serverDate.innerHTML = ev.data;
    }
    </script>
    <meta charset="UTF-8">
    <title>Server Sent Event</title>
</head>
<body>
    <section>
        <h2>Server Status</h2>
        <p id="serverStatus"></p>
    </section>
    <section>
        <h2>Server Date</h2>
        <p id="serverDate"></p>
    </section>
</body>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市竿音,隨后出現(xiàn)的幾起案子和屎,更是在濱河造成了極大的恐慌,老刑警劉巖春瞬,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柴信,死亡現(xiàn)場離奇詭異,居然都是意外死亡宽气,警方通過查閱死者的電腦和手機随常,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萄涯,“玉大人绪氛,你說我怎么就攤上這事±杂埃” “怎么了枣察?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長燃逻。 經(jīng)常有香客問我序目,道長,這世上最難降的妖魔是什么唆樊? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任宛琅,我火速辦了婚禮刻蟹,結(jié)果婚禮上逗旁,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好片效,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布红伦。 她就那樣靜靜地躺著,像睡著了一般淀衣。 火紅的嫁衣襯著肌膚如雪昙读。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天膨桥,我揣著相機與錄音蛮浑,去河邊找鬼。 笑死只嚣,一個胖子當(dāng)著我的面吹牛沮稚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播调鲸,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼藐石!你這毒婦竟也來了募狂?” 一聲冷哼從身側(cè)響起勺三,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎牡彻,沒想到半個月后扫沼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體出爹,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年缎除,在試婚紗的時候發(fā)現(xiàn)自己被綠了严就。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡器罐,死狀恐怖梢为,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轰坊,我是刑警寧澤铸董,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站肴沫,受9級特大地震影響袒炉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜樊零,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一我磁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驻襟,春花似錦夺艰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至豌习,卻和暖如春存谎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肥隆。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工既荚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人栋艳。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓恰聘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吸占。 傳聞我的和親對象是個殘疾皇子晴叨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容