、html頁(yè)面會(huì)緩存嗎?
單純的html頁(yè)面不會(huì)緩存,htm是一種標(biāo)記語(yǔ)言,用來(lái)描述和標(biāo)記的,不能實(shí)現(xiàn)緩存。html里面的JavaScript代碼是當(dāng)這個(gè)html頁(yè)面加載時(shí)瀏覽器解釋執(zhí)行,也不可以實(shí)現(xiàn)數(shù)據(jù)緩存。
二、html 頁(yè)面怎么對(duì)緩存進(jìn)行設(shè)置
根據(jù)服務(wù)器系統(tǒng)環(huán)節(jié)的不同設(shè)置方法不一樣
1、在Apache環(huán)境下
可以通過(guò)在.htaccess文件中添加下面的代碼,設(shè)置圖片的HTTP緩存和有效期(需要開(kāi)啟apache的headers模塊支持):
其中max-age后面這個(gè)數(shù)字就是設(shè)置的緩存有效期(以秒為單位),比如上面的代碼設(shè)置了網(wǎng)站的圖片使用為期一年(秒)的HTTP緩存。
2、在Nginx下
可以通過(guò)修改nginx.conf配置文件,來(lái)修改緩存設(shè)置:
location~*\.(flv|gif|jpg|jpeg|png|ico|swf)${;access_logoff;break;}
注意:同樣的方法,可以給js和css文件設(shè)置緩存。
html緩存:html5 應(yīng)用程序緩存和瀏覽器緩存有什么區(qū)別
應(yīng)用程序緩存是會(huì)預(yù)加載的,保證齊全地供應(yīng)和保存。瀏覽器緩存沒(méi)有這些控制,不能作為程序緩存使用。不幸地,應(yīng)用程序緩存過(guò)於簡(jiǎn)單,導(dǎo)致效率不彰,預(yù)期將會(huì)被ServiceWorker取代。
存是個(gè)老生長(zhǎng)談的問(wèn)題,對(duì)于前端工程師來(lái)講更是我們的必修課。或許很多人會(huì)說(shuō)我的項(xiàng)目并沒(méi)有問(wèn)題,根本不需要聊什么緩存。如果真的是這樣,只能證明你前端道路才剛剛開(kāi)始。
小郭今天分享緩存的原因在于:公司的一個(gè)核心APP中嵌入了SPA,而且應(yīng)用核心都分布在SPA中,功能復(fù)雜且重。問(wèn)題出現(xiàn)了:應(yīng)用核心頁(yè)面打開(kāi)一直處于加載狀態(tài),排除掉弱網(wǎng)環(huán)境的原因,重點(diǎn)就在于沒(méi)有緩存,每次進(jìn)入頁(yè)面都需要重載DOM和數(shù)據(jù),拖慢頁(yè)面打開(kāi)速度。
那應(yīng)該處理緩存問(wèn)題呢?接下來(lái)小郭從三個(gè)方向來(lái)講解。
在了解瀏覽器緩存前,我們需要先了解一下相關(guān)的概念:cache-control,expires,last-Modified,ETag。
瀏覽器通過(guò)請(qǐng)求頭實(shí)現(xiàn)緩存,關(guān)鍵的請(qǐng)求頭有cache-control,expires,last-Modified,ETag等。我們從時(shí)間和空間兩個(gè)角度來(lái)看瀏覽器緩存。
時(shí)間
瀏覽器發(fā)送第一次請(qǐng)求:不緩存,服務(wù)端根據(jù)設(shè)定的緩存策略返回相應(yīng)的header,如:cache-control,expires,last-Modified,ETag。
瀏覽器發(fā)送第二次請(qǐng)求:
空間
如果緩存就按理論上設(shè)置,那就太簡(jiǎn)單了。在實(shí)際應(yīng)用有個(gè)嚴(yán)重的問(wèn)題,我們不僅要緩存代碼,還需要更新代碼。如果靜態(tài)資源名字不變,怎么讓瀏覽器即能緩存又能在有新代碼時(shí)更新。最簡(jiǎn)單的解決方式就是靜態(tài)資源路徑添加一個(gè)版本值,版本不變就走緩存策略,版本變了就加載新資源。如下:
<script src="xx/xx.js?v=24334452"></script>
然而這種處理方式在部署時(shí)有問(wèn)題。
解決方法:靜態(tài)資源和頁(yè)面是分開(kāi)部署
這些問(wèn)題的本質(zhì)是以上的部署方式是“覆蓋式發(fā)布”,解決方式是“非覆蓋式發(fā)布”。即用靜態(tài)資源的文件摘要信息給文件命名,這樣每次更新資源不會(huì)覆蓋原來(lái)的資源,先將資源發(fā)布上去。這時(shí)候存在兩種資源,用戶用舊頁(yè)面訪問(wèn)舊資源,然后再更新頁(yè)面,用戶變成新頁(yè)面訪問(wèn)新資源,就能做到無(wú)縫切換。簡(jiǎn)單來(lái)說(shuō)就是給靜態(tài)文件名加hash值。
那如何實(shí)現(xiàn)呢?
現(xiàn)在前端代碼都用webpack之類的構(gòu)建工具打包,那么結(jié)合webpack該怎么做,怎么才能做到持久化緩存?
一、webpack給文件名添加hash值是很簡(jiǎn)單的,但hash/chunkhash/contenthash要用哪個(gè)呢?
官方定義
hash: unique hash generated for every build
chunkhash: hashes based on each chunks' content
contenthash: hashes generated for extracted content
根據(jù)分析,contenthash才是我們需要的,內(nèi)容有更新,hash值才會(huì)更新。
二、webpack會(huì)打包業(yè)務(wù)代碼、第三方庫(kù)及運(yùn)行時(shí)代碼,為保證緩存互不干擾,應(yīng)該將它們提取出來(lái)。
第三方庫(kù)提取方式是設(shè)置optimization的splitChunks的cacheGroups。splitChunks能提取模塊,cacheGroups能緩存模塊,并且cacheGroups的配置會(huì)覆蓋splitChunks相同配置,既能提取又能緩存,故只需設(shè)置cacheGroups。
運(yùn)行時(shí)代碼的提取方式為配置runtimeChunk,默認(rèn)為false,表示運(yùn)行時(shí)代碼嵌入到不同的chunk文件中;現(xiàn)在將運(yùn)行時(shí)代碼提取出來(lái),并命名為manifest。
module.exports = {
entry: {
index: "./src/index.js",
bar: "./src/bar.js"
},
output: {
filename: "[name].[contenthash].js"
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test:/[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
}
}
},
runtimeChunk: {
name: "manifest"
}
}
};
三、 moduleName 和 chunkName 對(duì)文件的影響
module:就是js模塊
chunk:webpack編譯過(guò)程中由多個(gè)module組成的文件
bundle:bundle是chunk文件的最終狀態(tài),是webpack編譯后的結(jié)果
一個(gè)文件被分離為3個(gè)文件,文件間怎么相互依賴的,會(huì)影響彼此打包,解決方法是將moduleId和chunkId改成按照文件路徑生成。
optimization: {
moduleIds: 'hashed',
namedModules: true,
namedChunks: true
}
這樣子moduleId在編譯后的文件是文件目錄的hash值,更加安全。這也是namedChunks在production默認(rèn)為false的原因,不想依賴的文件路徑在編譯后的文件直接展示,但是為了持久性緩存,這里也只能打開(kāi)。
四、CSS文件緩存
當(dāng)css代碼提取成單獨(dú)文件,當(dāng)我們改變css時(shí),怎么保證不影響引用它的js文件呢?配置如下:
plugins: [
new MiniCssExtractPlugin({
filename: "[contenthash].css"
})
]
webpack持久化緩存目標(biāo)是當(dāng)且僅當(dāng)該文件內(nèi)容變動(dòng)才改變?cè)撐募值膆ash值
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
output: {
filename: [name].[contenthash].js, // 讓hash值只在內(nèi)容變動(dòng)時(shí)更新
chunkFilename: [name].[contenthash].js // 動(dòng)態(tài)引入的模塊命名,同上
},
module: {
rules: [ {
test: /\.css$/,
use: [
"loader: MiniCssExtractPlugin.loader", // 提取出來(lái)css "css-loader"
]
} ]
},
optimization: {
moduleIds: "hashed", // 混淆文件路徑名
runtimeChunk: { name: 'manifest' }, // 提取runtime代碼命名為manifest
namedModules: true, // 讓模塊id根據(jù)路徑設(shè)置,避免每增加新模塊,所有id都改變,造成緩存失效的情況
namedChunks: true, // 避免增加entrypoint,其他文件都緩存失效
cacheGroups: {
vendor: { // 提取第三方庫(kù)文件
test: /[\\/]node_modules[\\/]/,
name: 'vendors', chunks: 'all',
},
},
}
plugins: [
new webpack.HashedModuleIdsPlugin(), // 與namedModules: true作用一樣
new MiniCssExtractPlugin({
filename: "[contenthash].css", // css文件也是按contenthash命名
chunkFilename: "[contenthash].css", // 動(dòng)態(tài)引入的css命名,同上
})
],
}
瀏覽器有其緩存機(jī)制,想要既能緩存又能在部署時(shí)沒(méi)有問(wèn)題,需要給靜態(tài)文件名添加hash值。在webpack中,有些配置能讓我們實(shí)現(xiàn)持久化緩存。感興趣的同學(xué)可以自行去測(cè)試哦!
有任何問(wèn)題可以在下方留言,想了解更多前端知識(shí)歡迎關(guān)注公眾號(hào)“一郭鮮”,文章也將同步于公眾號(hào),前端學(xué)習(xí)不迷路
用場(chǎng)景:
無(wú)論我們用PC端瀏覽網(wǎng)站還是用的移動(dòng)端,網(wǎng)站都會(huì)緩存一些CSS,JS等文件。尤其是JS,我們常會(huì)寫(xiě)些代碼,我之前曾在蘋果手機(jī)上多番嘗試都沒(méi)辦法清除緩存的文件。后面通過(guò)在JS后面增加版本號(hào)即可解決問(wèn)題。
那么,我們先來(lái)看看重現(xiàn)問(wèn)題,我們寫(xiě)的JS引用,如下圖:
以上是沒(méi)有版本號(hào)的,如果你修改了tool.min.js文件,并上傳到服務(wù)器。刷新該頁(yè)面后,仍然對(duì)新修改的不會(huì)有任何響應(yīng),因?yàn)榫彺媪恕?/p>
解決辦法:
在后面加上?V=xxx,版本號(hào),那么瀏覽器就會(huì)把它當(dāng)作一個(gè)新的文件,重新加載,如下圖:
當(dāng)然,我們作為一些長(zhǎng)期維護(hù)的網(wǎng)站,我們的版本號(hào)很可能更多的是這樣:
<script type="text/javascript" src="https://acstatic-dun.126.net/tool.min.js?v=2022031701"></script>
其中:
1)20220317代表的是今天的日期
2)最后兩位數(shù)字代碼的是當(dāng)天更新的第幾次。
這樣做了之后,無(wú)論我們?cè)谝苿?dòng)端還是PC端就不會(huì)出現(xiàn)緩存的現(xiàn)象。
當(dāng)然緩存這塊完全看瀏覽器,不排除有些瀏覽器仍然沒(méi)生效,那就只有清除瀏覽器緩存了。
不過(guò)怎么主流的IE瀏覽器,微信瀏覽器,GOOGLE器不會(huì)出現(xiàn)這個(gè)問(wèn)題。
歡迎加我,一起分享開(kāi)發(fā)的思路與代碼
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。