【问题标题】:How browser executes Javascript and renders asynchronously浏览器如何执行 Javascript 并异步呈现
【发布时间】:2014-12-10 09:14:06
【问题描述】:

这是jsfiddle上的代码

<script>
  function updateSync1() {
    for (var i = 0; i < 1000; i++) {
      document.getElementById('output').innerHTML = i;
    }
  }

  function updateSync2() {
    for (var i = 0; i < 1000; i++) {
      setTimeout(document.getElementById('output').innerHTML = i, 0);
    }
  }

  function updateAsync() {
    var i = 0;

    function updateLater() {
      document.getElementById('output').innerHTML = (i++);
      if (i < 1000) {
        setTimeout(updateLater, 0);
      }
    }

    updateLater();
  }
</script>

<div class="row btn_area">
  <button class="btn btn-info" onclick="updateSync1()">Run Sync 1</button>
  <button class="btn btn-info" onclick="updateSync2()">Run Sync 2</button>
  <button class="btn btn-info" onclick="updateAsync()">Run Async</button>
  <span class="label label-info pull-right" style="display:block;" id="output"></span>
</div>

http://jsfiddle.net/himaneasy/y1534ths/

当我点击“Run Sync 1”时,代码将直接运行到 999。

当我点击“Run Sync 2”时,代码会直接运行到 999。

当我点击“Run Async”时,页面会一一呈现。

谁能帮助解释 Run Sync1 和 Run Sync2 之间的区别? 为什么 Run Sync 2 中的 setTimeout 不让它一个一个渲染?

【问题讨论】:

    标签: javascript performance dom settimeout dom-events


    【解决方案1】:

    Javascript 执行是single-threaded。它使用任务队列和堆栈来执行任务。

    这段代码:

    for (var i=0;i<length;i++) {
         setTimeout(drawChartFunc,0);
    }
    

    将在任务队列中添加 [length] setTimeouts 调用并随后执行所有调用(0 毫秒超时)。只有最后一个操作会更新屏幕,因为所有超时任务都首先出现在堆栈上(循环之后,任务队列包含 [length] setTimeout 调用)。每次超时都会执行drawChartFunc。现在drawChartFunc确实在任务队列上放了一个屏幕更新功能,但是剩余的超时时间先到,所以首先执行下一个超时-屏幕更新功能只能在[长度]之后执行 setTimeout 调用已完成(从任务队列/堆栈中取出)。这也是随后完成的,但速度非常快。如果您的眼睛经过训练可以看到纳秒级的转换,您可能已经在输出中发现了随后的数字;)

    现在

    function updateLater() {
         drawChartFunc();
         i++;
         if (i < length) { 
             setTimeout(updateLater, 0);
         }
     }
    

    将首先运行 drawChartFunc 将屏幕更新放入任务队列,然后将增量 i 放入任务队列,然后 - 如果适用 - 之后将新的 setTimeout 添加到任务队列。换句话说,drawChartFunc 被放入堆栈,将屏幕更新放入堆栈,两者都被执行,随后超时被放入堆栈,将drawChartFunc 放入堆栈...等等。

    关于 javascript 任务队列/堆栈:this video 对我非常有用。

    这是您的jsFiddle,稍作改写。它向您展示了这两种方法的排队过程。

    【讨论】:

      【解决方案2】:

      setTimeout(callback, interval) 有两个参数:一个回调函数,以及执行它的时间间隔。 interval 参数确定callback 的执行速度:在您的情况下,0 毫秒,即尽快执行。 在您的代码中:

       function updateSync2() {
          for (var i = 0; i < 1000; i++) {
            setTimeout(document.getElementById('output').innerHTML = i, 0);
          }
        }
      

      您已经创建了 1000 个setTimeout 函数,它们都将尽快执行。

      【讨论】:

      • 不是“立即”。 setTimeout 仍然是异步的,这意味着“尽快”。
      • @Bergi 谢谢,是的,这是一个更好的表达方式。
      猜你喜欢
      • 1970-01-01
      • 2013-09-14
      • 1970-01-01
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 2019-06-19
      • 2016-06-24
      • 1970-01-01
      相关资源
      最近更新 更多