最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

實(shí)踐示例理解js強(qiáng)緩存協(xié)商緩存

 更新時間:2022年07月04日 16:40:29   作者:Sunshine_Lin  
這篇文章主要為大家以實(shí)踐示例理解js強(qiáng)緩存協(xié)商緩存,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

背景

無論是開發(fā)中或者是面試中,HTTP緩存都是非常重要的,這體現(xiàn)在了兩個方面:

  • 開發(fā)中:合理利用HTTP緩存可以提高前端頁面的性能
  • 面試中:HTTP緩存是面試中的高頻問點(diǎn)

所以本篇文章,我不講廢話,我就通過Nodejs的簡單實(shí)踐,給大家講最通俗易懂的HTTP緩存,大家通過這篇文章一定能了解掌握它?。?!

前置準(zhǔn)備

準(zhǔn)備

  • 創(chuàng)建文件夾cache-study,并準(zhǔn)備環(huán)境
npm init
  • 安裝Koa、nodemon
npm i koa -D
npm i nodemon -g
  • 創(chuàng)建index.js、index.html、static文件夾
  • index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./static/css/index.css" rel="external nofollow" >
</head>
<body>
  <div class="box">
  </div>
</body>
</html>
  • static/css/index.css
.box {
  width: 500px;
  height: 300px;
  background-image: url('../image/guang.jpg');
  background-size: 100% 100%;
  color: #000;
}
  • static/image/guang.jpg

  • index.js
const Koa = require('koa')
const fs = require('fs')
const path = require('path')
const mimes = {
  css: 'text/css',
  less: 'text/css',
  gif: 'image/gif',
  html: 'text/html',
  ico: 'image/x-icon',
  jpeg: 'image/jpeg',
  jpg: 'image/jpeg',
  js: 'text/javascript',
  json: 'application/json',
  pdf: 'application/pdf',
  png: 'image/png',
  svg: 'image/svg+xml',
  swf: 'application/x-shockwave-flash',
  tiff: 'image/tiff',
  txt: 'text/plain',
  wav: 'audio/x-wav',
  wma: 'audio/x-ms-wma',
  wmv: 'video/x-ms-wmv',
  xml: 'text/xml',
}
// 獲取文件的類型
function parseMime(url) {
  // path.extname獲取路徑中文件的后綴名
  let extName = path.extname(url)
  extName = extName ? extName.slice(1) : 'unknown'
  return mimes[extName]
}
// 將文件轉(zhuǎn)成傳輸所需格式
const parseStatic = (dir) => {
  return new Promise((resolve) => {
    resolve(fs.readFileSync(dir), 'binary')
  })
}
const app = new Koa()
app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    // 訪問根路徑返回index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    // 設(shè)置類型
    ctx.set('Content-Type', parseMime(url))
    // 設(shè)置傳輸
    ctx.body = await parseStatic(filePath)
  }
})
app.listen(9898, () => {
  console.log('start at port 9898')
})

啟動頁面

現(xiàn)在你可以在終端中輸入nodemon index,看到下方的顯示,則代表成功啟動了服務(wù)

此時你可以在瀏覽器鏈接里輸入http://localhost:9898/,打開看到如下頁面,則代表頁面訪問成功?。。?/p>

HTTP緩存種類

HTTP緩存常見的有兩類:

強(qiáng)緩存:可以由這兩個字段其中一個決定

  • expires
  • cache-control(優(yōu)先級更高)

協(xié)商緩存:可以由這兩對字段中的一對決定

Last-Modified,If-Modified-Since

Etag,If-None-Match(優(yōu)先級更高)

強(qiáng)緩存

接下來我們就開始講強(qiáng)緩存

expires

我們只需設(shè)置響應(yīng)頭里expires的時間為當(dāng)前時間 + 30s就行了

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    // 訪問根路徑返回index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    // 設(shè)置類型
    ctx.set('Content-Type', parseMime(url))
    // 設(shè)置 Expires 響應(yīng)頭
    const time = new Date(Date.now() + 30000).toUTCString()
    ctx.set('Expires', time)
    // 設(shè)置傳輸
    ctx.body = await parseStatic(filePath)
  }
})

然后我們在前端頁面刷新,我們可以看到請求的資源的響應(yīng)頭里多了一個expires的字段

并且,在30s內(nèi),我們刷新之后,看到請求都是走memory,這意味著,通過expires設(shè)置強(qiáng)緩存的時效是30s,這30s之內(nèi),資源都會走本地緩存,而不會重新請求

注意點(diǎn):有時候你Nodejs代碼更新了時效時間,但是發(fā)現(xiàn)前端頁面還是在走上一次代碼的時效,這個時候,你可以把這個Disabled cache打鉤,然后刷新一下,再取消打鉤

cache-control

其實(shí)cache-control跟expires效果差不多,只不過這兩個字段設(shè)置的值不一樣而已,前者設(shè)置的是秒數(shù),后者設(shè)置的是毫秒數(shù)

app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    // 訪問根路徑返回index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    // 設(shè)置類型
    ctx.set('Content-Type', parseMime(url))
    // 設(shè)置 Cache-Control 響應(yīng)頭
    ctx.set('Cache-Control', 'max-age=30')
    // 設(shè)置傳輸
    ctx.body = await parseStatic(filePath)
  }
})

前端頁面響應(yīng)頭多了cache-control這個字段,且30s內(nèi)都走本地緩存,不會去請求服務(wù)端

協(xié)商緩存

與強(qiáng)緩存不同的是,強(qiáng)緩存是在時效時間內(nèi),不走服務(wù)端,只走本地緩存;而協(xié)商緩存是要走服務(wù)端的,如果請求某個資源,去請求服務(wù)端時,發(fā)現(xiàn)命中緩存則返回304,否則則返回所請求的資源,那怎么才算命中緩存呢?接下來講講

Last-Modified,If-Modified-Since

簡單來說就是:

  • 第一次請求資源時,服務(wù)端會把所請求的資源的最后一次修改時間當(dāng)成響應(yīng)頭中Last-Modified的值發(fā)到瀏覽器并在瀏覽器存起來
  • 第二次請求資源時,瀏覽器會把剛剛存儲的時間當(dāng)成請求頭中If-Modified-Since的值,傳到服務(wù)端,服務(wù)端拿到這個時間跟所請求的資源的最后修改時間進(jìn)行比對
  • 比對結(jié)果如果兩個時間相同,則說明此資源沒修改過,那就是命中緩存,那就返回304,如果不相同,則說明此資源修改過了,則沒命中緩存,則返回修改過后的新資源
// 獲取文件信息
const getFileStat = (path) => {
  return new Promise((resolve) => {
    fs.stat(path, (_, stat) => {
      resolve(stat)
    })
  })
}
app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    // 訪問根路徑返回index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    const ifModifiedSince = ctx.request.header['if-modified-since']
    const fileStat = await getFileStat(filePath)
    console.log(new Date(fileStat.mtime).getTime())
    ctx.set('Cache-Control', 'no-cache')
    ctx.set('Content-Type', parseMime(url))
    // 比對時間,mtime為文件最后修改時間
    if (ifModifiedSince === fileStat.mtime.toGMTString()) {
      ctx.status = 304
    } else {
      ctx.set('Last-Modified', fileStat.mtime.toGMTString())
      ctx.body = await parseStatic(filePath)
    }
  }
})

第一次請求時,響應(yīng)頭中:

第二次請求時,請求頭中:

由于資源并沒修改,則命中緩存,返回304:

此時我們修改一下index.css

.box {
  width: 500px;
  height: 300px;
  background-image: url('../image/guang.jpg');
  background-size: 100% 100%;
  /* 修改這里 */
  color: #333;
}

然后我們刷新一下頁面,index.css變了,所以會沒命中緩存,返回200和新資源,而guang.jpg并沒有修改,則命中緩存返回304:

Etag,If-None-Match

其實(shí)Etag,If-None-Match跟Last-Modified,If-Modified-Since大體一樣,區(qū)別在于:

  • 后者是對比資源最后一次修改時間,來確定資源是否修改了
  • 前者是對比資源內(nèi)容,來確定資源是否修改

那我們要怎么比對資源內(nèi)容呢?我們只需要讀取資源內(nèi)容,轉(zhuǎn)成hash值,前后進(jìn)行比對就行了??!

const crypto = require('crypto')
app.use(async (ctx) => {
  const url = ctx.request.url
  if (url === '/') {
    // 訪問根路徑返回index.html
    ctx.set('Content-Type', 'text/html')
    ctx.body = await parseStatic('./index.html')
  } else {
    const filePath = path.resolve(__dirname, `.${url}`)
    const fileBuffer = await parseStatic(filePath)
    const ifNoneMatch = ctx.request.header['if-none-match']
    // 生產(chǎn)內(nèi)容hash值
    const hash = crypto.createHash('md5')
    hash.update(fileBuffer)
    const etag = `"${hash.digest('hex')}"`
    ctx.set('Cache-Control', 'no-cache')
    ctx.set('Content-Type', parseMime(url))
    // 對比hash值
    if (ifNoneMatch === etag) {
      ctx.status = 304
    } else {
      ctx.set('etag', etag)
      ctx.body = fileBuffer
    }
  }
})

驗(yàn)證方式跟剛剛Last-Modified,If-Modified-Since的一樣,這里就不重復(fù)說明了。。。

總結(jié)

參考 http://m.fzitv.net/article/254078.htm

以上就是實(shí)踐示例理解js強(qiáng)緩存協(xié)商緩存的詳細(xì)內(nèi)容,更多關(guān)于js強(qiáng)緩存協(xié)商緩存的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解如何讓頁面與?iframe?進(jìn)行通信

    詳解如何讓頁面與?iframe?進(jìn)行通信

    這篇文章主要為大家介紹了詳解如何讓頁面與?iframe?進(jìn)行通信實(shí)現(xiàn)實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 微信小程序 Page()函數(shù)詳解

    微信小程序 Page()函數(shù)詳解

    這篇文章主要介紹了微信小程序 Page()函數(shù)詳解的相關(guān)資料,在開發(fā)過程中肯定會遇到Page()函數(shù),希望能幫助到大家,需要的朋友可以參考下
    2016-10-10
  • JavaScript中塊級作用域與函數(shù)作用域深入剖析

    JavaScript中塊級作用域與函數(shù)作用域深入剖析

    這篇文章主要為大家介紹了JavaScript中塊級作用域與函數(shù)作用域的實(shí)現(xiàn)原理深入剖析,
    2023-05-05
  • javascript的setTimeout()使用方法總結(jié)

    javascript的setTimeout()使用方法總結(jié)

    這篇文章主要給大家分享javascript的setTimeout()使用方法總結(jié),js的setTimeout方法用處比較多,通常用在頁面刷新了、延遲執(zhí)行了等等,下面我們一起來看看文章對該內(nèi)容的具體總結(jié)吧,需要的朋友可以參考一下
    2021-11-11
  • 微信小程序 頁面跳轉(zhuǎn)傳參詳解

    微信小程序 頁面跳轉(zhuǎn)傳參詳解

    這篇文章主要介紹了微信小程序 頁面跳轉(zhuǎn)傳參詳解的相關(guān)資料,并附簡單實(shí)例,和實(shí)現(xiàn)效果圖,需要的朋友可以參考下
    2016-10-10
  • 微信小程序 教程之小程序配置

    微信小程序 教程之小程序配置

    這篇文章主要介紹了微信小程序 教程之小程序配置的相關(guān)資料,這里對app.json,pages,window等做了詳細(xì)介紹,對于初學(xué)開發(fā)微信小程序的朋友,掌握這些還是比較重要的,需要的朋友可以參考下
    2016-10-10
  • 微信小程序 彈框和模態(tài)框?qū)崿F(xiàn)代碼

    微信小程序 彈框和模態(tài)框?qū)崿F(xiàn)代碼

    這篇文章主要介紹了微信小程序 彈框和模態(tài)框?qū)崿F(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 一文詳解Electron?快捷鍵使用技巧及示例

    一文詳解Electron?快捷鍵使用技巧及示例

    這篇文章主要為大家介紹了Electron?中的快捷鍵使用技巧及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • javascript對象3個屬性特征

    javascript對象3個屬性特征

    這篇文章主要介紹了javascript對象3個屬性特征,writable可寫、enumerable可枚舉、configurable可配置,下面來看看文章的詳細(xì)內(nèi)容吧
    2021-11-11
  • autojs寫一個畫板實(shí)現(xiàn)AI換頭狗頭蛇

    autojs寫一個畫板實(shí)現(xiàn)AI換頭狗頭蛇

    這篇文章主要為大家介紹了autojs寫一個畫板實(shí)現(xiàn)AI換頭狗頭蛇過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01

最新評論

崇仁县| 营口市| 长治市| 聂荣县| 台北市| 清原| 绥中县| 高碑店市| 大冶市| 乐清市| 微博| 彭山县| 驻马店市| 扶余县| 凤冈县| 温泉县| 睢宁县| 鹤壁市| 府谷县| 霍邱县| 泸水县| 阿瓦提县| 寿光市| 仁怀市| 金塔县| 沙河市| 邳州市| 吴川市| 南雄市| 临洮县| 阆中市| 桃源县| 湘潭市| 北宁市| 石嘴山市| 唐海县| 福海县| 贞丰县| 竹溪县| 四子王旗| 邯郸市|