JavaScript 提升运行速度之循环篇

作者:性能诊所

时间:2026-10-23

浏览:421

本文探讨JavaScript中导致脚本失控的循环问题,提出通过评估同步性和顺序性来分解大循环。介绍使用chunk函数结合setTimeout将数组分批处理,避免浏览器锁定,并提供保留原数组副本的两种实现方式,以优化性能并防止警告。

文章目录

JavaScript 循环优化与脚本失控避免

本文重点分析导致脚本失控的第一个原因,并给出一种开发模式,通过替换传统的循环结构,彻底避免脚本失控的情况。


原文标题:Speed up your JavaScript, Part 1
原文作者:Nicholas C. Zakas
在上一篇译文中,讨论了各浏览器弹出脚本失控提示的条件。对于Internet Explorer,当执行语句数量过多时会停止脚本;其他浏览器则在脚本持续运行超过一定时间后给出提示。本文核心不在于浏览器如何检测失控脚本,而在于如何让脚本运行更快,从而避免这些警告。
脚本失控主要源于以下四个方面:
循环中执行了过多操作。
函数体过于臃肿
递归调用过多
DOM调用过于频繁
本文聚焦于第一点:循环中的过多操作。由于循环操作是同步执行的,其耗时完全取决于循环次数。导致循环时间过长并锁定浏览器的两种情况是:循环体内包含过多操作,或循环次数过多。这两种情况均会直接导致浏览器锁定并显示脚本失控提示。
解决该问题的关键在于用以下两个问题评估每个循环:
该循环是否必须同步执行?
循环内的数据是否必须按顺序执行?
若两个问题的答案均为否定,即可对循环内的操作进行分解。关键是根据代码具体环境确定上述两个问题的答案。一个典型循环可能如下所示:

代码示例如下:

 
for(var i=0; i < items.length; i++){
process(items[i]);
} 

乍看之下,该循环似乎并无大碍,其运行时长完全取决于循环次数。若循环后无其他代码依赖其结果,则第一个问题的答案为“否”。此外,循环每次仅处理一个数值且不依赖上一次结果,故第二个答案也为“否”。这意味着该循环可通过某种方式拆解,不会导致浏览器锁定或显示脚本失控提示。
在《Professional JavaScript, Second Edition》一书中,针对执行次数巨大的循环,推荐使用以下方式处理:

代码示例如下:

 
function chunk(array, process, context){
setTimeout(function(){
var item = array.shift();
process.call(context, item);
if (array.length > 0){
setTimeout(arguments.callee, 100);
} 
}, 100);
} 

chunk()函数的作用是将数组分块处理(这也是其名称由来),可传递三个参数:要处理的数组对象、处理函数以及一个可选的上下文变量,用于设置process()函数中的this对象。第一个timer用于处理操作间的延时(此处设为100毫秒,可根据实际需求调整)。每次执行该函数,都会取出数组第一个对象并传给process()函数处理;若process()中仍有未处理完的对象,则启动另一个timer重复等待。前述循环可通过以下方式使用该函数:
chunk(items, process);
需注意,此处数组采用队列(queue)形式,且在循环过程中每次都会发生修改。若需保留数组原始状态,这里提供两种途径:一种是通过concat()函数,在传递前建立当前数组的副本:
chunk(items.concat(), process);
另一种选择是直接修改chunk()函数,在函数内部进行修改:

代码示例如下:

 
function chunk(array, process, context){
var items = array.concat(); //clone the array
setTimeout(function(){
var item = items.shift();
process.call(context, item);
if (items.length > 0){
setTimeout(arguments.callee, 100);
} 
}, 100);
} 

注意,这种方法比仅保存索引安全得多,因为数组内容在下次计时器生效前可能会发生变化。
此处提到的chunk()函数仅是优化循环性能的起点。可根据需要不断改进,增加更多功能。例如,可在数组中所有对象处理完成后增加函数回调。无论是否按此方式修改函数,这都是一种JavaScript代码开发模式,有助于优化数组处理性能,并避免脚本失控警告。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章