使用定时器处理数组

368 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

循环问题

从常见的一个性能问题入手,循环会造成脚本运行时间过长。之前的循环优化如果还是没能减少足够的运行时间,那么你下一步就可以尝试的就是选用定时器。它的特性就是把循环的工作分解到一系列定时器中。 例如:

for(let i = 0, len = items.length; i < len; i++){
    run(items[i]);
}

这类循环结构运行时间长的主要原因是 run 的复杂度和 items 的大小。是否可用定时器取代循环的两个决定性因素:

  • 处理过程是否必须同步
  • 数据是否必须按顺序处理

符合上诉条件之后,就可以适用于定时器分解任务:

 function runArray(items, run, callback) {
     const items2 = items.concat();
     
     setTimeout(function(){
         run(items2.shift());
         
         if(items2.length > 0) {
             setTimeout(arguments.callee, 25)
         }else{
             callback(items);
         }
         
     }, 25)
 }

这个模式的基本思路是创建了一个原始数组的克隆,并将它作为数组项队列来处理。第一次调用 setTimeout() 创建了一个定时器处理数组的第一项。处理完后检查是否还有其他项,如果还有则再开启定时器,运行相同的代码,使用了 arguments.callee 实现。如果都处理完成,则调用 callback 回调函数。

分割任务

我们通常会把一个任务分解成一系列的子任务。如果一个函数运行时间过长,那么就可以尝试把他分解为能够在较短时间内完成的子任务。例如:

function savedocument(id){
    // 保存文件
    openDocument(id);
    writeText(id);
    closeDocuemnt(id);
    // 将处理完成后的信息更新至界面
    updateUI(id)
}

如果这个函数运行时间太长,可以很容易的把它拆分成一系列更小的步骤:

    fuction saveDocument(id){
        const tasks = [openDocument, writeText, closeDocument, updateUI];
        setTimeout(function(){
            const task = tasks.shift();
            task(id);
            
            if(tasks.length > 0){
                setTimeout(arguments.callee, 25);
            }
        }, 25)
    }

这个版本的函数把每个方法都放入 tasks 数组,然后每次在定时器中调用一个方法。唯一的区别在于处理数组条目时调用的函数就包含在条目中。再次封装以备复用:

    function multistep(steps, args, callback){
        const tasks = steps.concat();
        setTimeout(function(){
            const task = tasks.shift();
            task.apply(null, args || []);
            
            if(tasks.length > 0){
                setTimeout(arguments.callee, 25)
            }else{
                callback();
            }
        }, 25)
    }

multistep 函数接收三个参数:由函数组成的数组,为每个函数运行时提供参数的数组,结束后的回调。

定时器与性能

定时器会让你的 JavaScript 代码整体性能发生天翻地覆的变化。但是过度使用也会造成负面影响。当多个重复的定时器同时创建往往会造成性能问题。因为只有一个 UI线程, 而所有的定时器都在争夺运行时间。应当在你的 web 应用中限制高频率重复定时器的数量