摘要:瀏覽器緩存的使用是提高用戶體驗的一個重要途徑,通常也是優(yōu)化前端的一種重要方式。瀏覽器看到就會去讀取緩存信息并呈現(xiàn)。
瀏覽器緩存
瀏覽器緩存(Browser Caching)是為了節(jié)約網(wǎng)絡(luò)的資源加速瀏覽,瀏覽器在用戶磁盤上對最近請求過的文檔進行存儲,當訪問者再次請求這個頁面時,瀏覽器就可以從本地磁盤顯示文檔,這樣就可以加速頁面的閱覽。
瀏覽器緩存的使用是提高用戶體驗的一個重要途徑,通常也是優(yōu)化前端的一種重要方式。利用好了緩存可以加快頁面的瀏覽,降低服務(wù)器的壓力,減少網(wǎng)絡(luò)損耗等功能。
瀏覽器緩存分類協(xié)商緩存
強制緩存
協(xié)商緩存通過上圖分析:
客戶端向服務(wù)器請求資源
驗證標識,如果標識通過了驗證,則會響應(yīng)304,告知瀏覽器讀取緩存
如果沒有標識,或驗證沒有通過,則返回請求的資源
看到這里可能有人會有問題,標識是什么?
標識主要是用來標識請求的資源是否被修改或更新過,通過請求頭發(fā)送給服務(wù)器進行驗證。
協(xié)商緩存的標識有兩種:
ETag
Last-Modified
下面我們來講講這兩者的區(qū)別以及用法
Last-Modifiedlast-modified 根據(jù)詞義就可以知道表示該資源的最后修改時間。
客戶端第一次請求服務(wù)器,服務(wù)器會把該資源的最后修改時間通過響應(yīng)頭返回給客戶端
客戶端再次請求服務(wù)器的時候,如果在響應(yīng)頭中有Last-Modified字段,瀏覽器就會在請求頭中加上if-Modified-Since字段給服務(wù)器。
服務(wù)器拿到該字段的值,與該資源的最后修改時間進行對比,如果相等則說明資源沒有被修改,向客戶端返回304。
瀏覽器看到304就會去讀取緩存信息并呈現(xiàn)。
下面根據(jù)以上的幾個點,來看看代碼怎么實現(xiàn):
const http = require("http"); const url = require("url"); const path = require("path"); const fs = require("fs"); const mime = require("mime"); const server = http.createServer((req, res) => { // 獲取文件名 const { pathname } = url.parse(req.url, true); // 獲取文件路徑 const filepath = path.join(__dirname, pathname); /** * 判斷文件是否存在 */ fs.stat(filepath, (err, stat) => { if (err) { res.end("not found"); } else { // 獲取if-modified-since這個請求頭 const ifModifiedSince = req.headers["if-modified-since"]; // 獲取資源最后修改時間 let lastModified = stat.ctime.toGMTString(); // 驗證資源是否被修改過,如果相同則返回304讓瀏覽器讀取緩存 if (ifModifiedSince === lastModified) { res.writeHead(304); res.end(); } // 緩存沒有通過則返回資源,并加上 last-modified響應(yīng)頭,下次瀏覽器就會在請求頭中帶著 if-modified-since else { res.setHeader("Content-Type", mime.getType(filepath)); res.setHeader("Last-Modified", stat.ctime.toGMTString()); fs.createReadStream(filepath).pipe(res); } } }); }); server.listen(8000, () => { console.log("listen to 8000 port"); });ETag
ETag它的流程和last-modified是一樣的,僅僅只是驗證方式不同,last-modified是取的當前請求資源的最后修改時間來作為驗證,而ETag則是對當前請求的資源做一個唯一的標識。
標識可以是一個字符串,文件的size,hash等等,只要能夠合理標識資源的唯一性并能驗證是否修改過就可以了。比如讀取文件內(nèi)容,將文件內(nèi)容轉(zhuǎn)換成一個hash值,每次接收到客戶端發(fā)送過來的時候,重新讀取文件轉(zhuǎn)成hash值,與之前的做對比,看資源是否修改過。
和Last-Modify相同,服務(wù)器在響應(yīng)頭返回一個ETag字段,那么請求的時候就會在請求頭中加入if-none-match
下面來看看代碼,代碼中我都會加入詳細的注釋:
const http = require("http"); const url = require("url"); const path = require("path"); const fs = require("fs"); const mime = require("mime"); const crypto = require("crypto"); const server = http.createServer(function(req, res) { // 獲取請求的資源名稱 let { pathname } = url.parse(req.url, true); // 獲取文件路徑 let filepath = path.join(__dirname, pathname); /** * 判斷文件是否存在 */ fs.stat(filepath, (err, stat) => { if (err) { return sendError(req, res); } else { let ifNoneMatch = req.headers["if-none-match"]; let readStream = fs.createReadStream(filepath); let md5 = crypto.createHash("md5"); // 通過流的方式讀取文件并且通過md5進行加密,相當于轉(zhuǎn)成一個hash字符串作為etag的值 readStream.on("data", function(data) { md5.update(data); }); readStream.on("end", function() { let etag = md5.digest("hex"); // 驗證etag,判斷資源是否被修改過,如果沒有則返回304 if (ifNoneMatch === etag) { res.writeHead(304); res.end(); } else { res.setHeader("Content-Type", mime.getType(filepath)); // 第一次服務(wù)器返回的時候,會把文件的內(nèi)容算出來一個標識,發(fā)給客戶端 fs.readFile(filepath, (err, content) => { // 客戶端看到etag之后,也會把此標識保存在客戶端,下次再訪問服務(wù)器的時候,發(fā)給服務(wù)器 res.setHeader("Etag", etag); fs.createReadStream(filepath).pipe(res); }); } }); } }); }); server.listen(8000, () => { console.log("listen to 8000 port"); });強制緩存
通過上圖分析:
強制緩存通過Cache-Control這個響應(yīng)頭中的max-age:60(緩存60s)來判斷緩存是否過期
如果過期了則重新向服務(wù)器請求資源
如果沒有過期,則不經(jīng)過服務(wù)器,直接讀取資源
強制緩存比較簡單,直接看一下代碼的實現(xiàn)
const http = require("http"); const url = require("url"); const path = require("path"); const fs = require("fs"); const mime = require("mime"); const server = http.createServer(function(req, res) { let { pathname } = url.parse(req.url, true); let filepath = path.join(__dirname, pathname); fs.stat(filepath, (err, stat) => { if (err) { res.setHeader("Content-Type", mime.getType(filepath)); // 設(shè)置緩存過期時間 res.setHeader("Cache-Control", "max-age=100"); fs.createReadStream(filepath).pipe(res); } else { return send(req, res, filepath); } }); }); server.listen(8000, () => { console.log("listen to port 8000"); });
強制緩存就是向瀏覽器設(shè)置一個過期時間例如cache-control:max-age=60表示這是一個60秒的過期時間,60秒以內(nèi)瀏覽器都會從緩存讀取該資源,超過60秒則訪問服務(wù)器
cache-control還有另外幾個值可以設(shè)置
private 客戶端可以緩存
public 客戶端和代理服務(wù)器都可以緩存
max-age=60 緩存內(nèi)容將在60秒后失效
no-cache 需要使用對比緩存驗證數(shù)據(jù),強制向源服務(wù)器再次驗證
no-store 所有內(nèi)容都不會緩存,強制緩存和對比緩存都不會觸發(fā)
總結(jié)理解緩存對前端開發(fā)來說十分的重要,這也是為何把這篇文章寫出來的原因,后續(xù)會繼續(xù)為大家?guī)韓ode相關(guān)的文章,如果寫錯或不好的地方希望大家指出來,如果覺得寫的還行,麻煩點個贊哈!
以下我的新個人微信公眾號,也會為大家持續(xù)提供原創(chuàng)文章,歡迎大家關(guān)注,如果用戶量足夠,會在里面為大家提供一些項目類的視頻教程,謝謝
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/108931.html
摘要:先天就缺乏一項功能模塊通過標簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。與文件模塊區(qū)別地方在于它從內(nèi)存中加載緩存執(zhí)行結(jié)果的位置核心模塊在對象上,文件模塊在對象上未完待續(xù) javascript先天就缺乏一項功能:模塊 javasciprt 通過script標簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。人們不得不用命名空間等方式人為地約束代碼,以求達到安全和易用的...
摘要:概述本文主要介紹了我對的一些核心特性的理解,包括架構(gòu)特點機制核心模塊與簡單應(yīng)用。在此期間,主線程繼續(xù)執(zhí)行其他任務(wù)。延續(xù)了瀏覽器端單線程,只用一個主線程執(zhí)行,不斷循環(huán)遍歷事件隊列,執(zhí)行事件。 原文地址在我的博客,轉(zhuǎn)載請注明來源,謝謝! node是在前端領(lǐng)域經(jīng)??吹降脑~。node對于前端的重要性已經(jīng)不言而喻,掌握node也是作為合格的前端工程師一項基本功了。知道node、知道后端的一些東西...
摘要:模塊載入策略的模塊分為兩類,一類為原生核心模塊,一類為文件模塊。最后傳入對象的,方法,,文件名,目錄名作為實參并執(zhí)行。在這個主文件中,可以通過方法去引入其余的模塊。以上所描述的模塊載入機制均定義在中。 CommonJS規(guī)范? 早在Netscape誕生不久后,JavaScript就一直在探索本地編程的路,Rhino是其代表產(chǎn)物。無奈那時服務(wù)端JavaScript走的路均是參考眾多服務(wù)器端...
閱讀 3529·2021-11-22 11:59
閱讀 945·2021-09-27 13:36
閱讀 3603·2021-09-24 09:47
閱讀 2251·2021-09-01 11:39
閱讀 970·2021-08-31 09:37
閱讀 2304·2021-08-05 10:01
閱讀 1665·2019-08-30 15:55
閱讀 694·2019-08-30 15:54