浏览器如何异步执行Javascript和渲染

How browser executes Javascript and renders asynchronously

本文关键字:Javascript 执行 异步 何异步 浏览器      更新时间:2023-09-26

这是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 Async"时,页面将逐个呈现。

有人能解释一下Run Sync1&是否运行Sync2?为什么Run Sync 2中的setTimeout不能逐个渲染?

Javascript的执行是单线程的。它使用任务队列和堆栈来执行内容。

这段代码:

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

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

现在

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

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

隐藏javascript任务队列/堆栈:这个视频对我来说真的很有用。

这是您的jsFiddle,经过一点重写。它向您展示了这两种方法的排队过程。

setTimeout(callback, interval)有两个参数:回调函数和执行该函数的间隔。interval参数决定了callback的执行时间:在您的情况下,为0毫秒,即尽可能快。在您的代码中:

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

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