原文链接: fre 代码优化
上一篇: benchmarkjs 测试函数性能
下一篇: MessageChannel 实现worker之间的通信
一个比较小的框架, 想看看实现原理, 结果看到这样的代码.....
const hashfy = c => {
const out = {}
c.pop
? c.forEach((v, i) =>
v.pop
? v.forEach((vi, j) => (out[hs(i, j, vi.key)] = vi))
: (out[hs(i, null, v.key)] = v)
)
: (out[hs(0, null, c.key)] = c)
return out
}
const hs = (i, j, k) =>
k != null && j != null
? '.' + i + '.' + k
: j != null
? '.' + i + '.' + j
: k != null
? '.' + k
: '.' + i
代码主要作用是将dom结构转化为一个k-v形式的对象, 用于做diff
每个节点的key是路径的节点的 key或者index
但是这个代码只支持最多二维数组, 如果三维的话会报错
<div>
{Array(3).fill().map((x, i) =>
Array(3).fill().map((y, j) =>
Array(3).fill().map((z, k) => (
<div>
{i},{j},{k}
</div>
)
)
)
)}
</div>
想着这种用递归比较好处理, 就先写了递归版本
const hashfy = c => {
const isArray = Array.isArray
if (!c || (isArray(c) && !c.length)) return {}
if (!isArray(c)) return { [c.key || '.0']: c }
let out = {}
function walk(value, key = '') {
if (!isArray(value)) {
out[key] = value
return
}
value.forEach((elem, index) => {
let k = elem.key || index
!isArray(value) ? (out[path + '.' + k] = elem) : walk(elem, key + '.' + k)
})
}
walk(c)
return out
}
被告知1万节点会爆栈, 于是改成stack模拟
const hashfy = c => {
const isArray = Array.isArray
if (!c || (isArray(c) && !c.length)) return {}
if (!isArray(c)) return { [c.key || '.0']: c }
let out = {}
const keyList = [0]
const getCurInfo = () => {
let key = ''
let list = c
let elem = c
for (let i = 0; i < keyList.length; i++) {
elem = elem[keyList[i]]
key += '.' + (elem.key || keyList[i])
if (i < keyList.length - 1) list = list[keyList[i]]
}
return { elem, list, key }
}
while (keyList.length) {
let { elem, list, key } = getCurInfo()
if (!isArray(elem)) {
out[key] = elem
keyList[keyList.length - 1]++
while (list.length === keyList[keyList.length - 1]) {
keyList.pop()
list = getCurInfo().list
keyList.length && keyList[keyList.length - 1]++
}
continue
}
if (list.length > 0) keyList.push(0)
else {
keyList[keyList.length - 1]++
}
}
return out
}
不过在测试中, 这三种实现的速度都差不了多少, 我电脑加两万节点也没啥事....就是有点卡