淺聊快取函式

語言: 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 日更文 ✍ 陪你一起度過漫長歲月 🌏