We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本文为读 lodash 源码的第一百八十一篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
import ListCache from './ListCache.js' import MapCache from './MapCache.js'
《lodash源码分析之List缓存》
《lodash源码分析之缓存方式的选择》
lodash 中设计了 Hash 、Map 和 List 等数据结构来做缓存。
lodash
Hash
Map
List
其中 Hash 本质上是使用对象来做缓存,这会使得 Hash 会在一些场景上会有使用限制,只能使用字符串或者 Symbol 来做 key 。但是 Map 和 List 则没有这些限制。
Symbol
key
Stack 所做的,其实是动态切换 Map 和 List 缓存,因为 List 本质上是使用数组对来进行缓存,当缓存比较大时,会有性能问题,因此在缓存长度超过一定数量时,会切换到 Map 缓存。
Stack
Stack 所提供的接口和 Map 及 List 一致。
源码如下:
const LARGE_ARRAY_SIZE = 200 class Stack { constructor(entries) { const data = this.__data__ = new ListCache(entries) this.size = data.size } clear() { this.__data__ = new ListCache this.size = 0 } delete(key) { const data = this.__data__ const result = data['delete'](key) this.size = data.size return result } get(key) { return this.__data__.get(key) } has(key) { return this.__data__.has(key) } set(key, value) { let data = this.__data__ if (data instanceof ListCache) { const pairs = data.__data__ if (pairs.length < LARGE_ARRAY_SIZE - 1) { pairs.push([key, value]) this.size = ++data.size return this } data = this.__data__ = new MapCache(pairs) } data.set(key, value) this.size = data.size return this } }
constructor(entries) { const data = this.__data__ = new ListCache(entries) this.size = data.size }
传入的是[[key, value], ...] 这样形式的数组,初始化一个 ListCache 实例,用私有属性 __data__ 保存 ListCache 实例,后面可能会切换成 MapCache 实例。
[[key, value], ...]
ListCache
__data__
MapCache
用 size 来保存缓存的长度。
size
clear() { this.__data__ = new ListCache this.size = 0 }
clear 方法来清空缓存。
clear
其实就是新创建一个 ListCache 实例,但是没有传入任何参数给 constructor 。
constructor
size 也重置为 0 。
0
delete(key) { const data = this.__data__ const result = data['delete'](key) this.size = data.size return result }
其实就是调用 ListCache 或者 MapCache 上的 delete 方法,删除对应的 key 。
delete
在删除的同时,也更新 size 。
get(key) { return this.__data__.get(key) }
获取缓存上的值,也是简单的方法委托。
has(key) { return this.__data__.has(key) }
判断某个 key 是否已有缓存,也是简单的方法委托。
Stack 最主要的是 set 的方法,就是在这个方法里实现了 List 和 Set 数据结构的切换。
set
Set
set(key, value) { let data = this.__data__ if (data instanceof ListCache) { const pairs = data.__data__ if (pairs.length < LARGE_ARRAY_SIZE - 1) { pairs.push([key, value]) this.size = ++data.size return this } data = this.__data__ = new MapCache(pairs) } data.set(key, value) this.size = data.size return this }
首先判断 data 是否为 ListCache 的实例,如果是 ListCache 的实例,则从实例的私有属性 __data__ 里取出原始数据 pairs,pairs 的形式如:[[key, value],...]
data
pairs
[[key, value],...]
实现数据结构的切换关键在于 pairs 的长度,lodash 这里设定的长度为 LARGE_ARRAY_SIZE - 1 ,即在小于 199 时,会使得 ListCache 。
LARGE_ARRAY_SIZE - 1
199
如果使用的是 ListCache ,则将 [key, value] 直接 push 进 pairs 里即可,同时更新 size 和 ListCache 实例的 size。即 this.size = ++data.size 。
[key, value]
push
this.size = ++data.size
这里不直接使用 ListCache 的实例的 set 方法,我猜应该是出于性能的考虑,因为 ListCache 实例的 set 方法会做重复性检测,这会损耗一部分性能。而 Stack 是内部方法,在使用的时候会避免重复,因此在 set 的时候不需要这部分检测。
否则就切换成 MapCache 结构,构建实例时将 pairs 传给 MapCache 的构造方法。
接下来就是用 MapCache 实例的 set 方法来设置 key 和 value ,然后再更新 size 。
value
Stack 手动来管理 size,而且在多个地方都要更新 size ,其实可以利用 getter 来避免手动管理。
getter
代码如下:
class Stack { get size () { return this.__data__.size } }
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
The text was updated successfully, but these errors were encountered:
No branches or pull requests
本文为读 lodash 源码的第一百八十一篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash
gitbook也会同步仓库的更新,gitbook地址:pocket-lodash
依赖
《lodash源码分析之List缓存》
《lodash源码分析之缓存方式的选择》
源码分析
lodash
中设计了Hash
、Map
和List
等数据结构来做缓存。其中
Hash
本质上是使用对象来做缓存,这会使得Hash
会在一些场景上会有使用限制,只能使用字符串或者Symbol
来做key
。但是Map
和List
则没有这些限制。Stack
所做的,其实是动态切换Map
和List
缓存,因为List
本质上是使用数组对来进行缓存,当缓存比较大时,会有性能问题,因此在缓存长度超过一定数量时,会切换到Map
缓存。Stack
所提供的接口和Map
及List
一致。源码如下:
constructor
传入的是
[[key, value], ...]
这样形式的数组,初始化一个ListCache
实例,用私有属性__data__
保存ListCache
实例,后面可能会切换成MapCache
实例。用
size
来保存缓存的长度。clear
clear
方法来清空缓存。其实就是新创建一个
ListCache
实例,但是没有传入任何参数给constructor
。size
也重置为0
。delete
其实就是调用
ListCache
或者MapCache
上的delete
方法,删除对应的key
。在删除的同时,也更新
size
。get
获取缓存上的值,也是简单的方法委托。
has
判断某个
key
是否已有缓存,也是简单的方法委托。set
Stack
最主要的是set
的方法,就是在这个方法里实现了List
和Set
数据结构的切换。源码如下:
首先判断
data
是否为ListCache
的实例,如果是ListCache
的实例,则从实例的私有属性__data__
里取出原始数据pairs
,pairs
的形式如:[[key, value],...]
实现数据结构的切换关键在于
pairs
的长度,lodash
这里设定的长度为LARGE_ARRAY_SIZE - 1
,即在小于199
时,会使得ListCache
。如果使用的是
ListCache
,则将[key, value]
直接push
进pairs
里即可,同时更新size
和ListCache
实例的size
。即this.size = ++data.size
。这里不直接使用
ListCache
的实例的set
方法,我猜应该是出于性能的考虑,因为ListCache
实例的set
方法会做重复性检测,这会损耗一部分性能。而Stack
是内部方法,在使用的时候会避免重复,因此在set
的时候不需要这部分检测。否则就切换成
MapCache
结构,构建实例时将pairs
传给MapCache
的构造方法。接下来就是用
MapCache
实例的set
方法来设置key
和value
,然后再更新size
。题外话
Stack
手动来管理size
,而且在多个地方都要更新size
,其实可以利用getter
来避免手动管理。代码如下:
License
署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)
最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:
作者:对角另一面
The text was updated successfully, but these errors were encountered: