美文网首页
使用 setTimeout 拆解一些 CPU 密集型的执行任务

使用 setTimeout 拆解一些 CPU 密集型的执行任务

作者: _扫地僧_ | 来源:发表于2022-05-21 10:04 被阅读0次

    未优化之前的版本:

    let i = 0;
    
    let start = Date.now();
    
    function count() {
    
      // do a heavy job
      for (let j = 0; j < 1e9; j++) {
        i++;
      }
    
      alert("Done in " + (Date.now() - start) + 'ms');
    }
    
    count();
    

    上述 count 函数里的 for 循环的 i 累加,是一个 CPU 密集型任务,在执行完毕之前,JavaScript 引擎任务队列里的其他任务,没有机会得到执行。

    优化版本

    将 i 从 1 累加到 1e9 的任务,拆解成 1000 个小的子任务。每个子任务执行完毕之后,调用 setTimeout 调度自身,这样任务队列里其他任务有机会得到执行。

    let i = 0;
    
    let start = Date.now();
    
    function count() {
    
      // do a piece of the heavy job (*)
      do {
        i++;
      } while (i % 1e6 != 0);
    
      if (i == 1e9) {
        alert("Done in " + (Date.now() - start) + 'ms');
      } else {
        setTimeout(count); // schedule the new call (**)
      }
    
    }
    
    count();
    
    • 第一轮任务执行:i=1...1000000
    • 第二轮任务执行:i=1000001..2000000

    以此类推。

    现在,如果在引擎忙于执行第 1 部分时出现新的辅助任务(例如 onclick 事件),它会排队,然后在第 1 部分完成时执行,然后再执行下一部分。 在 count 执行之间,使用 setTimeout 定期返回事件循环,为 JavaScript 引擎提供了调度执行其他任务的机会,以对其他用户操作做出反应。

    let i = 0;
    
    let start = Date.now();
    
    function count() {
    
      // move the scheduling to the beginning
      if (i < 1e9 - 1e6) {
        setTimeout(count); // schedule the new call
      }
    
      do {
        i++;
      } while (i % 1e6 != 0);
    
      if (i == 1e9) {
        alert("Done in " + (Date.now() - start) + 'ms');
      }
    
    }
    
    count();
    

    为浏览器脚本拆分 CPU 密集型任务的另一个好处是我们可以显示进度指示。

    如前所述,只有在当前运行的任务完成后才会绘制对 DOM 的更改,无论当前运行的任务需要多长时间才能执行完毕。

    下面是一个例子:

    <div id="progress"></div>
    
    <script>
    
      function count() {
        for (let i = 0; i < 1e6; i++) {
          i++;
          progress.innerHTML = i;
        }
      }
    
      count();
    </script>
    

    对 i 的更改要等到函数执行完成后才会显示,所以我们只会看到最后一个值。

    但我们也可能想在任务期间展示一些东西,例如一个进度条。

    如果我们使用 setTimeout 将繁重的任务拆分为多个部分,那么 i 会在多个部分执行之间绘制出来。

    <div id="progress"></div>
    
    <script>
      let i = 0;
    
      function count() {
    
        // do a piece of the heavy job (*)
        do {
          i++;
          progress.innerHTML = i;
        } while (i % 1e3 != 0);
    
        if (i < 1e7) {
          setTimeout(count);
        }
    
      }
    
      count();
    </script>
    

    相关文章

      网友评论

          本文标题:使用 setTimeout 拆解一些 CPU 密集型的执行任务

          本文链接:https://www.haomeiwen.com/subject/wwjuurtx.html