lodash原始碼分析之快取方式的選擇

2021-08-14 21:01:17 字數 4542 閱讀 9143

每個人心裡都有一團火,路過的人只看到煙。

——《至愛梵谷·星空之謎》

本文為讀 lodash 原始碼的第八篇,後續文章會更新到這個倉庫中,歡迎 star:pocket-lodash

在《lodash原始碼分析之hash快取》和《lodash原始碼分析之list快取》介紹了 lodash 的兩種快取方式,這兩種快取方式都實現了和map一致的資料管理介面,其中list快取只在不支援map的環境中使用,那何時使用hash快取,何時使用map或者list快取呢?這就是mapcache類所需要做的事情。

從之前的分析可以看出,hash快取完全可以用list快取或者map來代替,為什麼 lodash 不乾脆統一用一種快取方式呢?

原因是在資料量較大時,物件的訪問比map或者陣列的效能要好。

因此,ladash 在能夠用hash快取時,都盡量使用hash快取,而能否使用hash快取的關鍵是key的型別。

以下便為 lodash 決定使用快取方式的流程:

首先,判斷key的型別,以是否為string/number/symbol/boolean型別為成兩撥,如果是以上的型別,再判斷key是否等於__proto__,如果不是__proto__,則使用hash快取。不能為__proto__的原因是,大部分 js 引擎都以這個屬性來儲存物件的原型。

如果不是以上的型別,則判斷key是否為null,如果為null,則依然使用hash快取,其餘的則使用map或者list快取。

從上面的流程圖還可以看到,在可以用hash來快取的key中,還以是否為string型別分成了兩個hash物件來快取資料,為什麼要這樣呢?

我們都知道,物件的key如果不是字串或者symbol型別時,會轉換成字串的形式,因此如果快取的資料中同時存在像數字1和字串'1'時,資料都會儲存在字串'1'上。這兩個不同的鍵值,最後獲取的都是同乙份資料,這明顯是不行的,因此需要將要字串的key和其他需要轉換型別的key分開兩個hash物件儲存。

mapcache所做的事情有點像函式過載,其呼叫方式和hashmaplistcache一致。

new mapcache([

['key', 'value'],

[, 1],

[symbol(),2]

])

所返回的結果如下:

,

hash: ,

map:

}}

可以看到,__data__裡根據key的型別分成了stringhashmap三種型別來儲存資料。其中stringhash都是hash的例項,而map則是maplistcache的例項。

mapcache同樣實現了跟map一致的資料管理介面,如下:

import hash from './hash.js'

import listcache from './listcache.js'

《lodash原始碼分析之hash快取》

《lodash原始碼分析之list快取》

function

getmapdata

(, key)

function

iskeyable

(value)

class mapcache

} clear()

} delete(key)

get(key)

has(key)

set(key, value)

}

function

iskeyable

(value)

這個函式用來判斷是否使用hash快取。返回true表示使用hash快取,返回false則使用map或者listcache快取。

這個在流程圖上已經解釋過,不再作詳細的解釋。

function

getmapdata

(, key)

這個函式根據key來獲取儲存了該key的快取例項。

__data__即為mapcache例項中的__data__屬性的值。

如果使用的是hash快取,則型別為字串時,返回__data__中的string屬性的值,否則返回hash屬性的值。這兩者都為hash例項。

否則返回map屬性的值,這個可能是map例項或者listcache例項。

constructor(entries) 

}

構造器跟hashlistcache一模一樣,都是先呼叫clear方法,然後呼叫set方法,往快取中加入初始資料。

clear() 

}

clear是為了清空快取。

這裡值得注意的是__data__屬性,使用hashstringmap來儲存不同型別的快取資料,它們之間的區別上面已經論述清楚。

這裡也可以清晰地看到,如果在支援map的環境中,會優先使用map,而不是listcache

has(key)
has用來判斷是否已經有快取資料,如果快取資料已經存在,則返回true

這裡呼叫了getmapdata方法,獲取到對應的快取例項(hashmap或者listcache的例項),然後呼叫的是對應例項中的has方法。

set(key, value)
set用來增加或者更新需要快取的值。set的時候需要同時維護size和快取的值。

這裡除了呼叫對應的快取例項的set方法來維護快取的值外,還需要維護自身的size屬性,如果增加值,則加1

get(key)
get方法是從快取中取值。

同樣是呼叫對應的快取例項中的get方法。

delete(key)
delete方法用來刪除指定key的快取。成功刪除返回true, 否則返回false。 刪除操作同樣需要維護size屬性。

同樣是呼叫對應快取例項中的delete方法,如果刪除成功,則需要將自身的size的值減少1

署名-非商業性使用-禁止演繹 4.0 國際 (cc by-nc-nd 4.0)

lodash原始碼分析之List快取

昨日我沿著河岸 漫步到 蘆葦彎腰喝水的地方 順便請煙囪 在天空為我寫一封長長的信 潦是潦草了些 而我的心意 則明亮亦如你窗前的燭光 稍有曖昧之處 勢所難免 因為風的緣故 洛夫 因為風的緣故 本文為讀 lodash 原始碼的第七篇,後續文章會更新到這個倉庫中,歡迎 star pocket lodash...

lodash原始碼分析之Number

一 lodash版本 4.17.5 二 函式 1 clamp 1 定義 clamp number,lower upper 2 作用 返回加緊的數字。3 例子。const require lodash console.log clamp 10,1,20 輸出 10 console.log clamp ...

lodash原始碼分析之isArguments

有人命中註定要過平庸的生活,默默無聞,因為他們經歷了痛苦或不幸 有人卻故意這樣做,那是因為他們得到的幸福超過了他們的承受能力。卡爾維諾 煙雲 本文為讀 lodash 原始碼的第二十一篇,後續文章會更新到這個倉庫中,歡迎 star pocket lodash import gettag from in...