Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How browser executes Javascript and renders asynchronously

Here is the code on 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/

when I click 'Run Sync 1' the code will run to 999 directly.

When I click 'Run Sync 2',the code will run to 999 directly.

When I click 'Run Async',the page will render one by one.

Can anyone help explain the difference between Run Sync1 & Run Sync2? Why setTimeout in Run Sync 2 does not make it render one by one?

like image 561
jason zhong Avatar asked Feb 12 '23 19:02

jason zhong


1 Answers

Javascript execution is single-threaded. It uses a task queue and the stack to execute stuff.

This piece of code:

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

Will add [length] setTimeouts calls on the task queue and excute all of them subsequently (0 ms timeout). Only the last operation will update the the screen, because all of the timeout tasks come first on the stack (after the loop, the task queue contains [length] setTimeout calls). Every timeout executes drawChartFunc. Now drawChartFunc does put a screen update function on the task queue, but the remaining timeouts come first, so first the next timeout is executed - the screen update functions can only be executed after the [length] setTimeout calls are finished (taken of the task queue/stack). This is also done subsequently, but very fast. If your eyes where trained to see nanosecond transitions, you may have spotted the subsequent numbers in the output ;)

Now

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

Will first run drawChartFunc putting the screen update on the task queue, then put increment i on the task queue and - if applicable - after that add a new setTimeout to the task queue. In other words, drawChartFunc is put on the stack, that puts the screen update on the stack, both are executed, an subsequently the timeout is put on the stack, putting drawChartFunc on the stack ... etc.

Concering the javascript task queue/stack: this video was really useful to me.

Here's your jsFiddle, rewritten a bit. It shows you the queuing process for both methods.

like image 199
KooiInc Avatar answered Feb 15 '23 10:02

KooiInc