淺聊緩存函數

語言: CN / TW / HK

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第9天,點擊查看活動詳情


前文,我們已經聊過了:柯里化函數、偏函數,根據高階函數的定義:

高階函指使用其他函數作為參數、或者返回一個函數作為結果的函數。

柯里化函數、偏函數,都是妥妥的高階函數!傳入一個原函數,返回一個新函數。新函數繼承了原函數的能力,又發展出不同的新能力!!

牛哇牛哇,初級前端開發,用函數封裝過程,高級前端開發,用函數封裝函數。

本篇再介紹一個新的高階函數 —— 緩存函數

image.png


什麼是緩存函數?什麼情況下需要用到緩存函數?

本篇將用以下這個場景來解釋:

比方説,我們這裏有一個非常耗時的計算函數:

``` const calculate = (num)=>{ const startTime = new Date() for(let i=0;i<num;i++){} // 大數計算 const endTime = new Date() return endTime - startTime } console.log(calculate(10_000_000_000))

// 10465 ```

遍歷數字 100 億,需耗時 10s +,打印出這個值;

問:有什麼辦法能夠緩存下來這個值,等到下次再次調用 calculate(10_000_000_000) 的時候,不需要再次進行計算,直接就輸出這個計算結果??

有人説:着還不簡單嗎,直接把結果付給一個變量,let result = calculate(10_000_000_000) ,下次直接拿 result的值不就行了嗎?

從實現上講,當然是可以的;不過,從設計模式的角度來講,就不太ok了!

為什麼?

因為聲明 result 變量作為一個全局變量要一直存在,不管未來你用或者不用,它都存在着,佔用着內存;

設想下,如果有 N 個大數的計算,要寫 N 個變量去存嗎?即使有一些是後面不會再重複被調用了的。

let result = calculate(10_000_000_000) let result1 = calculate(10_000_000_0000) ...... let resultN = calculate(10_000_000_0000...000)

又有朋友説了:“我有好主意”!

我直接聲明一個緩存對象,再改寫 calculate 函數內部,計算的時候判斷一下,算過了的,就從對象裏面拿,沒算過的,才會進行計算。

代碼如下:

``` let cacheObj = {}

const calculate = (num)=>{ if(!cacheObj[num]){ const startTime = new Date() for(let i=0;i<num;i++){} const endTime = new Date() cacheObj[num] = endTime - startTime } return cacheObj[num] } ```

本瓜不得不説:你這孩子打小就聰明!

但是,忘記開閉原則了嗎?我們儘量要少修改原函數,而是儘量在其基礎上去拓展它。

這次是 calculate 函數需要緩存,下次,可能是 balculatedalculate ,難道還要去改這些函數的內部判斷嗎?

當然不!!緩存函數就是來解決這種困境的!!

代碼如下:

``` / * 緩存函數 cashed /

function cached(fn){ // 傳入需要緩存結果的函數

const cacheObj = Object.create(null); // 創建一個對象

return function cachedFn (str) { // 返回回調函數 if ( !cacheObj [str] ) { // 在對象裏面查詢,函數結果是否被計算過 let result = fn(str); cacheObj [str] = result; // 沒有則要執行原函數,並把計算結果緩存起來 } return cacheObj [str] // 被緩存過,直接返回 } }

// calculate 計算大數的函數(也可以叫原函數) const calculate = (num)=>{ const startTime = new Date() for(let i=0;i<num;i++){} const endTime = new Date() return endTime - startTime } // 經過緩存函數 cashed 將原函數 calculate 封裝,讓原函數具有緩存的新功能 let cashedCalculate = cached(calculate)

cashedCalculate(10_000_000_000) // 10465 ```

計算結果,就已經被緩存到 cashedCalculate 裏面了,我們再次調用:

cashedCalculate(10_000_000_000) // 10465

會立即得到計算結果 !


小結:

哈哈,就是這樣巧妙的思路,如果問緩存函數的究極奧義是啥?

本瓜會答:是閉包!閉包太強了,用 cached 函數處理 calculate 的時候,就留下了一個閉包對象 cacheObj ,一直被存儲着。並且返回的是回調函數,一樣去接收後續的參數。

這樣,既避免了多次創建全局變量,也避免了多次修改原函數內部。

用函數封裝函數,高級!!

OK,以上便是本篇分享。點贊關注評論,為好文助力👍

我是掘金安東尼 🤠 100 萬閲讀量人氣前端技術博主 💥 INFP 寫作人格堅持 1000 日更文 ✍ 陪你一起度過漫長歲月 🌏