欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解JavaScript 中的批處理和緩存

 更新時(shí)間:2020年11月19日 09:27:31   作者:rxliuli  
這篇文章主要介紹了詳解JavaScript 中的批處理和緩存,幫助大家完成需求,更好的理解和使用JavaScript,感興趣的朋友可以了解下

場景

最近在生產(chǎn)環(huán)境遇到了下面這樣一個(gè)場景:
后臺在字典表中存儲了一些之前需要前后端共同維護(hù)的枚舉值,并提供根據(jù) type/id 獲取字典的 API。所以在渲染列表的時(shí)候,有很多列表的字段直接就是字典的 id,而沒有經(jīng)過后臺的數(shù)據(jù)拼裝。

起初,吾輩解決問題的流程如下

  1. 確定字典字段,添加轉(zhuǎn)換后的對象類型接口
  2. 將對象列表進(jìn)行轉(zhuǎn)換得到其中字典字段的所有值
  3. 對字典 id 列表進(jìn)行去重
  4. 根據(jù) id 列表從后臺獲取到所有的字典數(shù)據(jù)
  5. 將獲得的字典數(shù)據(jù)轉(zhuǎn)換為 id => 字典 的 Map
  6. 遍歷最初的列表,對里面指定的字典字段進(jìn)行轉(zhuǎn)換

可以看到,上面的步驟雖然不麻煩,但卻十分繁瑣,需要定義額外的類型不說,還很容易發(fā)生錯(cuò)誤。

思路

  • 使用 異步批處理 + LRU 緩存 優(yōu)化性能
  • 支持異步 formatter 獲得更好的使用體驗(yàn)

實(shí)現(xiàn)異步批處理

參考實(shí)現(xiàn):

import { wait } from '../async/wait'

/**
 * 將多個(gè)并發(fā)異步調(diào)用合并為一次批處理
 * @param handle 批處理的函數(shù)
 * @param ms 等待的時(shí)長(時(shí)間越長則可能合并的調(diào)用越多,否則將使用微任務(wù)只合并一次同步執(zhí)行的所有調(diào)用)
 */
export function batch<P extends any[], R extends any>(
 handle: (list: P[]) => Promise<Map<P, R | Error>>,
 ms: number = 0,
): (...args: P) => Promise<R> {
 //參數(shù) => 結(jié)果 映射
 const resultCache = new Map<string, R | Error>()
 //參數(shù) => 次數(shù)的映射
 const paramCache = new Map<string, number>()
 //當(dāng)前是否被鎖定
 let lock = false
 return async function (...args: P) {
  const key = JSON.stringify(args)
  paramCache.set(key, (paramCache.get(key) || 0) + 1)
  await Promise.all([wait(() => resultCache.has(key) || !lock), wait(ms)])
  if (!resultCache.has(key)) {
   try {
    lock = true
    Array.from(
     await handle(Array.from(paramCache.keys()).map((v) => JSON.parse(v))),
    ).forEach(([k, v]) => {
     resultCache.set(JSON.stringify(k), v)
    })
   } finally {
    lock = false
   }
  }
  const value = resultCache.get(key)!
  paramCache.set(key, paramCache.get(key)! - 1)
  if ((paramCache.get(key) || 0) <= 0) {
   paramCache.delete(key)
   resultCache.delete(key)
  }
  if (value instanceof Error) {
   resultCache.delete(key)
   throw value
  }
  return value as R
 }
}

實(shí)現(xiàn)批處理的基本思路如下

1.使用 Map paramCache 緩存?zhèn)魅氲?參數(shù) => 剩余調(diào)用次數(shù)(該參數(shù)還需要查詢幾次結(jié)果)
2.使用 Map resultCache 緩存 參數(shù) => 結(jié)果
3.使用 lock 標(biāo)識當(dāng)前是否有函數(shù)正在執(zhí)行
4.滿足以下條件需要等待
       Map 中不包含結(jié)果
       目前有其它調(diào)用在執(zhí)行
       還未滿最小等待時(shí)長(收集調(diào)用的最小時(shí)間片段)
5.使用 lock 標(biāo)識正在執(zhí)行
6.判斷是否已經(jīng)存在結(jié)果
       如果不存在則執(zhí)行批處理處理當(dāng)前所有的參數(shù)
7.從緩存 Map 中獲取結(jié)果
8.將 paramCache 中對應(yīng)參數(shù)的 剩余調(diào)用次數(shù) -1
9.判斷是否還需要保留該緩存(該參數(shù)對應(yīng)的剩余調(diào)用次數(shù)為 0)
       不需要則刪除
10.判斷緩存的結(jié)果是否是 Error
        是的話則 throw 拋出錯(cuò)誤

LRU 緩存

參考: Wiki 緩存算法, 實(shí)現(xiàn) MemoryCache

問:這里為什么使用緩存?
答:這里的字典接口在大概率上是冪等的,所以可以使用緩存提高性能
問:那么緩存策略為什么要選擇 LRU 呢?
答:毫無疑問 FIFO 是不合理的
問:那為什么不選擇 LFU 算法呢?它似乎能保留訪問最頻繁的資源
答:因?yàn)樽值浔聿⒎峭耆珒绲?,吾輩希望避免一種可能–訪問最多的字典一直沒有刪除,而它在數(shù)據(jù)庫已經(jīng)被更新了。

大致實(shí)現(xiàn)思路如下

1.使用一個(gè) Map 記錄 緩存 key => 最后訪問時(shí)間
2.每次獲取緩存時(shí)更新最后訪問時(shí)間
3.添加新的緩存時(shí)檢查緩存數(shù)量
          如果超過最大數(shù)量,則刪除最后訪問時(shí)間距離現(xiàn)在最長的一個(gè)緩存
4.添加新的緩存
Pass: 不要吐槽性能很差啦,這個(gè)場景下不會緩存特別多的元素啦,最多也就不到 1000 個(gè)吧

結(jié)合高階函數(shù)

現(xiàn)在,我們可以結(jié)合這兩種方式了,同時(shí)使用 onceOfSameParam/batch 兩個(gè)高階函數(shù)來優(yōu)化 根據(jù) id 獲取字典信息 的 API 了。

const getById = onceOfSameParam(
 batch<[number], Dict>(async (idList) => {
  if (idList.length === 0) {
   return new Map()
  }
  // 一次批量處理多個(gè) id
  const list = await this.getByIdList(uniqueBy(idList.flat()))
  return arrayToMap(
   list,
   (dict) => [dict.id],
   (dict) => dict,
  )
 }, 100),
)

支持異步 formatter

原本想要支持 ListTable 的異步 formatter 函數(shù),但后來想想,如果 slot 里也包含字典 id 呢?那是否 slot 也要支持異步呢?這可是個(gè)比較棘手的問題,所以還是不支持好了。

最終,吾輩在組件與 API 之間添加了 *Service 中間層負(fù)責(zé)處理數(shù)據(jù)轉(zhuǎn)換。

以上就是詳解JavaScript 中的批處理和緩存的詳細(xì)內(nèi)容,更多關(guān)于JavaScript 中的批處理和緩存的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Egg.js構(gòu)建一個(gè)stream流式接口服務(wù)實(shí)現(xiàn)詳解

    Egg.js構(gòu)建一個(gè)stream流式接口服務(wù)實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了Egg.js構(gòu)建一個(gè)stream流式接口服務(wù)實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • JS+Canvas實(shí)現(xiàn)動態(tài)時(shí)鐘效果

    JS+Canvas實(shí)現(xiàn)動態(tài)時(shí)鐘效果

    這篇文章主要為大家詳細(xì)介紹了JS+Canvas實(shí)現(xiàn)動態(tài)時(shí)鐘效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • JavaScript 數(shù)組- Array的方法總結(jié)(推薦)

    JavaScript 數(shù)組- Array的方法總結(jié)(推薦)

    下面小編就為大家?guī)硪黄狫avaScript 數(shù)組- Array的方法總結(jié)(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-07-07
  • XMLHTTPRequest的屬性和方法簡介

    XMLHTTPRequest的屬性和方法簡介

    由于現(xiàn)在在公司負(fù)責(zé)制作標(biāo)準(zhǔn)的靜態(tài)頁面,為了增強(qiáng)客戶體驗(yàn),所以經(jīng)常要做些AJAX效果,也許你也和我一樣在,學(xué)習(xí)AJAX。
    2010-11-11
  • element-ui 時(shí)間選擇器限制范圍的實(shí)現(xiàn)(隨動)

    element-ui 時(shí)間選擇器限制范圍的實(shí)現(xiàn)(隨動)

    這篇文章主要介紹了element-ui 時(shí)間選擇器限制范圍(隨動),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-01-01
  • openlayers實(shí)現(xiàn)圖標(biāo)拖動獲取坐標(biāo)

    openlayers實(shí)現(xiàn)圖標(biāo)拖動獲取坐標(biāo)

    這篇文章主要為大家詳細(xì)介紹了openlayers實(shí)現(xiàn)圖標(biāo)拖動獲取坐標(biāo),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • JavaScript禁止右擊保存圖片,禁止拖拽圖片的實(shí)現(xiàn)代碼

    JavaScript禁止右擊保存圖片,禁止拖拽圖片的實(shí)現(xiàn)代碼

    這篇文章主要介紹了JavaScript禁止右擊保存圖片,禁止拖拽圖片的實(shí)現(xiàn)代碼,代碼簡單易懂,非常不錯(cuò),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 詳解微信小程序應(yīng)用和頁面生命周期

    詳解微信小程序應(yīng)用和頁面生命周期

    生命周期是指一個(gè)對象從創(chuàng)建→>運(yùn)行>銷毀的整個(gè)階段,強(qiáng)調(diào)的是一個(gè)時(shí)間段,文中介紹了生命周期的分類和微信小程序應(yīng)用,需要的朋友可以參考下
    2022-08-08
  • JavaScript Perfection kill 測試及答案

    JavaScript Perfection kill 測試及答案

    近日,在Perfection kill上看到有關(guān)javascript quiz。并做了一下,最終錯(cuò)了2個(gè)(#2,#9),但是,這2道題,在Ie和ff下的答案是不一樣的?!
    2010-03-03
  • 微信小程序?qū)崿F(xiàn)消息框彈出動畫

    微信小程序?qū)崿F(xiàn)消息框彈出動畫

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)消息框彈出動畫,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06

最新評論