1

最近在给公司的grid组件进行性能测试和改善,其中非常重要的一个点就是grid加载100k级别的数据时,竟然出现的状况是,渲染不是问题,初始化的时候遍历数据才是问题。

之所以渲染不是问题,是因为组件采用了特殊的渲染方式,它并没有把所有数据一次性渲染到可视区域中,而是通过滚动条的计算,找出对应应该显示的那些条目,仅仅渲染了部分数据,所以加入的DOM节点就少到可怜,自然快很多。

现在的问题,完全放在了初始化的时候,要对这么大的数据量进行遍历,并且对每一个cell的数据执行format操作,可想而知,在不同的机器上,性能自然受到很大的影响。

我所采用的解决方案,是利用HTML5的新特性web worker来解决。worker的应用场景本来就是在backend进行大规模或持久化计算,用在这里正好。之所以在遍历的时候被卡住,就是因为我们遍历的时候,占用js主线程,导致其他程序无法进行。就算使用Promise优化,也会因为排队造成排队之后的操作被卡住。worker是在主线程之外另外开了一个线程,和主线程完全隔离,因此在内存分配上和进程占用上都不一样,worker线程中的程序执行完全不影响主线程中的执行。因此,将主线程中一个可能需要用到500+ms的计算移到另外一个线程中,主线程程序可以无缝继续执行,通过Promise来接收worker线程返回的数据,做到无缝对接。

下面来看具体实现:

1 获取quicker-worker源码

quicker-worker是我在结合了自己对其他开发者的代码阅读之后撰写的两个函数,站在前人的肩膀上倍感愉悦~

你可以通过 https://github.com/tangshuang... 获取源码。

2 使用run函数

在quicker-worker的readme中我详细阐述了它的使用方法,这里就不具体介绍,为了解决上面的grid的问题,我们使用run函数来实现对grid组件的改造。

在grid组件中,有一个遍历,在遍历过程中,对每一个元素进行format。我们如下进行操作:

// .. 其他初始化
run(`function(data, formatter) {
    data.forEach(function(item) {
        formatter(item)
    })
    return data
}`, [data, formatter])
.then(data => {
    this.set(data)
    // .. 后续操作
})

就是这么简单,没有任何拖泥带水的操作,就像一个promise一样。

使用quicker-worker还可以实现非常漂亮的后台监控,每隔一段时间去查询数据是否变化。

let wk = create(`function(data, compare) {
  return $xhr.get('/api/books').then(function(res) {
    if (compare(data, res)) return res
  })
}`, {
  interval: 60*1000,
  xhr: true,
})
wk.invoke([data, compare]).then(newdata => {
  if (newdata) updateData(newdata)
})

就是这么简单。如果你有什么疑问,可以在github上给我提issue。关注我的博客 www.tangshuang.net 给我留言。


否子戈
2.2k 声望143 粉丝

疯狂前端开发中……