场景:
有100个li,点击 button 时,给 li 添加一个 class,然后再执行一个 for 循环
代码
<script>
$('.btn').on('click', function () {
$('li').addClass('add')
for (var i = 0; i < 100000; i++) {
console.log(i)
}
});
</script>
问题
1、发现每次执行这个 click 事件时,都必须要执行完 for 后才能给 li 添加 class,这是为什么?
2、每次执行 click 时,里面的循环是不可少的,如果优化这个循环?
首先你要明白,浏览器不是一个整体,它有几大模块,JS 运行时(V8),渲染引擎(blink),主线程(处理插件、自动更新等),所以你在 JS 里操作 DOM,并不会直接反应到 DOM 上,而是由 V8 通知 blink。
重新渲染很花时间,如果需要 relayout 和 repaint 就更花时间。所以,为了避免
a.classList.add('add')
->a.classList.remove('add')
->a.classList.add('add')
->a.classList.remove('add')
-> .... 这样反复循环浪费渲染效率,浏览器会缓存你对 DOM 的修改,在当前 JS 栈执行完毕后,再一次性修改完,一次性 relayout + repaint。所以你会看到,虽然你已经在 JS 里给某个 DOM 节点加上了样式,但实际你只修改了它在 V8 里的映像,它的本体其实还没变。直到 JS 执行完才变。
第二个问题,我觉得是你实现的问题。作为前端,很忌讳让某个操作的时间能够被用户感知,如果这个操作需要很久,那么一方面你可以像楼上所说,通过
setTimeout
把它放到下个时间节点;另一方面,你应该好好考虑从算法的角度,是不是真有必要跑这么久的循环。