Why the huge time difference between while and do..while in JavaScript
Asked Answered
C

3

8

The while loop

Test the condition and if it is true, then execute the code

The do..while loop

Execute first time. Then test and execute.

So the difference between while and do..while is , programmatically In while, one test is carried out more than do while

That is

If a loop from 1 to 50 execute in while loop with one statement, it will have 51 tests(50 true and 1 false) and the statement will execute 50 times.

Similarly

If a loop from 1 to 50 execute in do..while loop with one statement, it will have 50 tests(1st test will not be carried out) and the statement will execute 50 times.

So, only one test/check less. that's it.

But when I tested the time taken for executing, it shows large difference.

function whileFn() {
  var i = 0;
  while (i < 10) {
    document.write(i);
    i++;
  }
}

function doWhileFn() {
  var i = 0;
  do {
    document.write(i);
    i++;
  } while (i < 10)
}

console.time('whileFn');
whileFn();
console.timeEnd('whileFn');

document.write('<br/>');

console.time('doWhileFn');
doWhileFn();
console.timeEnd('doWhileFn');

As you can see on the image and code exampe, the while loop took 15ms where as do while took only 5 ms.

What is the reason behind this huge different?

Test for 10 elements

enter image description here

Update as suggested by @pid

Test for 1000

enter image description here

took 23mS for 1 extra test

Test for 10000

enter image description here

397.91 mS more for 1 extra test

Test is carried on

Chrome (58.0.3029.110)

Edge 14

Ci answered 11/6, 2017 at 6:47 Comment(0)
T
19

EDIT: I HAVE AN ANSWER (TL;DR: SKIP TO THE END)

I've done some tests on my own.

function whileFn() {
  var i = 0;
  while (i < 10) {
    document.write(i);
    i++;
  }
}

function doWhileFn() {
  var i = 0;
  do {
    document.write(i);
    i++;
  } while (i < 10)
}


console.time('doWhileFn');
doWhileFn();
console.timeEnd('doWhileFn');

document.write('<br/>');

console.time('whileFn');
whileFn();
console.timeEnd('whileFn');

I've inverted the two functions and the timing is still the same. That is, the first is always slower than the second one. This is proof that the loop has no meaning whatsoever, it is completely bound by the rendering engine. (rendering is irrelevant)

If you remove document.write() altogether, the difference is reduced even more. (irrelevant)

To correctly measure the time, you have to take into account the measurement of time itself, in fact this shows the overhead of measuring time:

console.time('outer');
console.time('inner');
for (var i = 0; i < 10; i++);
console.timeEnd('inner');
console.timeEnd('outer');

The difference between the inner and outer measurement is a measurement overhead and impacts on the measurement itself (Heisenberg anyone?) so much that timing very fast functions (next to the ms mark) is prone to measurement errors. TRUE BUT IRRELEVANT

Try wrapping your code in huge cycles (like repeat 1000-100000 times) to reduce the impact of measurement. THIS PROVES TO BE NOT THE CASE

By the above statement long cycles would have a tiny measurement difference, but tests show that the difference scales with the number of cycles, and as such is NOT just a measurement overhead.

To recap the findings so far:

  • it is not a matter of while and do..while, because inverting the order of the two functions does not invert the timing: the first always is the slower one;
  • it is not a matter of measurement overhead because the difference scales to macroscopic proportions (it should be a variable, yet tiny amount -- but it's not);
  • it is not about rendering because I've removed it altogether at some point;
  • the inner-outer snippet shows that long cycles have a tiny measurement overhead by replacing 10 with a large number, but this is not the case for the original code in the question -- here the difference is proportional to the number of cycles.

EDIT: conclusion

This is an alternating test. Measure A, B, A again, B again and finally A again: the more you move forward, the more it converges.

Proof:

function whileFn() {
  var i = 0;
  while (i < 10) {
    document.write(i);
    i++;
  }
}

function doWhileFn() {
  var i = 0;
  do {
    document.write(i);
    i++;
  } while (i < 10)
}


console.time('doWhileFn');
doWhileFn();
console.timeEnd('doWhileFn');

document.write('<br/>');

console.time('whileFn');
whileFn();
console.timeEnd('whileFn');

document.write('<br/>');

console.time('doWhileFn');
doWhileFn();
console.timeEnd('doWhileFn');

document.write('<br/>');

console.time('whileFn');
whileFn();
console.timeEnd('whileFn');

document.write('<br/>');

console.time('doWhileFn');
doWhileFn();
console.timeEnd('doWhileFn');

Explanation: the JS engine compiles the source JS into native code on-the-fly. It has gradual performance scaling, but it can only compile a function AFTER it has returned. This means that the function is compiled and gradually optimized over a longer period of time. This, in fact, is a well known feature of V8. What is measured in the A-B scenario is not representative because of this edge condition (initial measures are inaccurate). The A-B-A-B-A scenario shows that A and B converge over time and measurements settle when they are far away from the edge (initial) condition.

Tootsie answered 11/6, 2017 at 7:1 Comment(7)
+1 for the explanation. But based on your first answer, I carried out tests for 1000 and 10000 in different order. Please check the images in the question. It show huge difference. ~400 mS for 10KCi
@SagarV Time measurement in JS is not accurate or precise. Varying system load can produce varying time difference in JS for the same piece of code. For example if I setup a timeout and then do one run on no load and another run on 100%cpu (rendering a video), etc..the timeout will not fire exactly at the same interval for both scenario. To be more accurate there is some thing called process.hrtime().This might help: #11726191Culbreth
@SagarV Yes I see! That's very curious. Still, inverting the order does change the measurement, so it's not about while vs do..while. It's something else altogether, but I am buffled right now :)Tootsie
Will this be the same with the V8 v5.9 (as the process of interpreting and compiling has changed, with turbofan and ignition)?Haulm
@Haulm Yes, the process hasn't changed that much, and the conclusion (optimisation is affected by execution) remains the same.Alginate
@Tootsie great explanation :)Photoelasticity
@pid: fiuu! you saved me from switching 300K lines of code from while... to do..while!Wallraff
H
0

There is actually very little difference. The perceived problem occurs because of the calling of document.write() in the timed code. The following simple code shows no significant difference between do and while:

let REPEATS = 1e7;

function play() {
    let start = undefined;
    let count = undefined;
    let elapsedWhile = undefined;
    let elapsedDo = undefined;
    let x = undefined;

    start = Date.now();
    count = REPEATS;
    while(count >0) {
        x = Math.sqrt(Math.random());
        count -= 1;
    }
    elapsedWhile = Date.now() - start;

    start = Date.now();
    count = REPEATS;
    do {
        x = Math.sqrt(Math.random());
        count -= 1;
    }while(count >0);    
    elapsedDo = Date.now() - start;

    console.log(elapsedWhile, elapsedDo);

}

function init() {
    xreport ('OK');
    var formx = document.getElementById("f1");;
    formx.X.addEventListener('click', play);
}

Try it here:http://www.johnwheater.net/JAVASCRIPT/PLAY3/html/main.html

Hymn answered 27/6, 2017 at 16:40 Comment(0)
S
0

This question is not only for JS, rather it applies to other languages as well, In most simple words, the "while" loop is "Entry controlled", and the "do-while" loop is "Exit controlled".

While loop: the code will only execute if a certain condition is met,

Do-While: the code will execute first and then it will check for condition, and if the condition is false, then the time taken in execution is wasted.

example: suppose you have a very long-running task, you will want the code to check for the condition first and then execute it, you will use while loop in that case, but in cases where, you want your code to execute at least once, irrespective of the condition, then you will use a do-while loop.

Thank you :;

Shanelleshaner answered 12/2 at 7:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.