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)緩存功能热凹?
- 創(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);即使有個空格都不行览徒。NETWORK和FALLBACK的書寫順序沒有強制要求狈定。
- manifest文件內(nèi)容一旦被改動,瀏覽器會根據(jù)最新的manifest文件規(guī)則更新進行緩存习蓬。
- 若web文件同時在CACHE MANIFEST和NETWORK標題下出現(xiàn)纽什,瀏覽器會將文件進行緩存處理,即CACHE MANIFEST優(yōu)先級比NETWORK高
- 緩存的文件來源兩個地方:一是CACHE MANIFEST標題下的文件躲叼,二是FALLBACK中無法訪問時的回退頁面(如404頁面)
- 若manifest屬性被定義芦缰,那么需要訪問網(wǎng)絡(luò)的所有文件都需要寫在NETWORK標題下。因此NETWORK標題下的內(nèi)容常用
*
通配符表示
- 在
<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>