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