浏览器如何执行javascript&渲染异步

时间:2014-10-15 10:19:02

标签: javascript performance dom javascript-events settimeout

以下是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/

当我点击“运行同步1”时,代码将直接运行到999.

当我点击“运行同步2”时,代码将直接运行到999.

当我点击“运行异步”时,页面将逐一呈现。

任何人都可以帮助解释Run Sync1&amp;运行Sync2? 为什么运行同步2中的setTimeout不能逐个渲染? 谢谢!

2 个答案:

答案 0 :(得分:6)

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

这段代码:

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

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

现在

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

首先运行drawChartFunc将屏幕更新放在任务队列上,然后将增量i放在任务队列上,并且 - 如果适用 - 之后向任务添加新的setTimeout队列。换句话说,drawChartFunc放在堆栈上,将屏幕更新放在堆栈上,两者都执行,随后超时放在堆栈上,放置{{1}在堆栈上......等等。

确认javascript任务队列/堆栈:this video对我来说非常有用。

这是你的jsFiddle,重写了一下。它显示了两种方法的排队过程。

答案 1 :(得分:0)

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

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

您已创建了1000个setTimeout函数,这些函数都会尽快执行。