1

I just can't understand why this code makes 1 second delay.

In my view, the result should always be zero because Date.now() will give me the same result - the present.

enter image description here

I reviewed closure, and Date.now() function but still have no idea.

The code is from the below link (tetris making tutorial on Youtube) and it is for a tetromino to get down in a second.

The code I can't understand is as follows.

let dropStart = Date.now();
console.log(dropStart)

function drop(){
    let now = Date.now();
    let delta = now - dropStart;       // I guess the result will always be zero !
    if(delta > 1000) {                 // how delta could be more than 1000 ?
        console.log(delta);
    };
}
 
drop();

Code is discussed on this YouTube video https://youtu.be/HEsAr2Yt2do?t=3533 Source code is available at https://github.com/CodeExplainedRepo/Tetris-JavaScript/blob/master/tetris.js

** the code appears at 59:21 **

enter image description here

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
BBiYak
  • 29
  • 5
  • 1
    What result are you seeing and what result were you expecting? If I run your code, I get one console log of a number (from `dropStart`) and then the function returns `undefined`. The delta is always less than 1000 and the second console log isn't executed. Try replacing the logs of the timestamps with `console.log('Start ' + dropStart)` and `console.log('Delta ' + delta)`. You'll see that the second isn't executed. – anotherdave Jun 22 '20 at 10:09
  • Could you update your YouTube link to contain the exact moment they talk about this bit? – Max Carroll Jun 22 '20 at 10:10
  • 1
    Unable to reproduce in the snippet – adiga Jun 22 '20 at 10:13
  • simply you miss to show us how drop is called in the real code. It will probably be called with a delay or repeatedly and when the if inside is successful a second has passed and the code will stop repeating calls to the function. But you are not showing ALL the relevant code and a MVCE to reproduce – Lelio Faieta Jun 22 '20 at 10:35

2 Answers2

1

So dropStart is defined outside the drop function and the drop function is called multiple times since there is a call to requestAnimationFrame(drop) also the drop function is called after dropStart is declared so there is likely to be a difference anyway since the code is not executed at the same time, how can we expect the timeDelta to be zero.

Also your code doesn't include this, but from the code in the snippet you were copying the requestAnimationFrame(drop) will cause this code to be called over and over again, so thats why the delta will be different each time. Every time the drop function is called it will instantiate a new date object and compare that to the one in global scope dropStart . So with every call to drop() we would expect the time difference to increase since we are travelling forwards in time.

Depending on what other code is going on I may or may not expect to see the first few calls to this drop function return less than 1000 ms, (I would guess not with most likely assumptions, although who knows without all the code). But after 1s (1000ms) I would then expect the condition (delta > 1000) to be true.

I think perhaps what you are missing here, is that this method is called over and over again due to the call to requestAnimationFrame(drop).

This answer is based on the assumption you didn't realise this method was being called multiple times.

From looking at the source code available at https://github.com/CodeExplainedRepo/Tetris-JavaScript/blob/master/tetris.js I can see that some events reset the dropStart time to Date.now()

  • pushing "Up", "Left" or "Right" on the keyboard
function CONTROL(event){
    if(event.keyCode == 37){
        p.moveLeft();
        dropStart = Date.now();
    }else if(event.keyCode == 38){
        p.rotate();
        dropStart = Date.now();
    }else if(event.keyCode == 39){
        p.moveRight();
        dropStart = Date.now();
    }else if(event.keyCode == 40){
        p.moveDown();
    }
}

  • when the delta is greater than a 1000 it resets itself anyway (here's a more complete version of the method from the source code
let dropStart = Date.now();
let gameOver = false;
function drop(){
    let now = Date.now();
    let delta = now - dropStart;
    if(delta > 1000){
        p.moveDown();
        dropStart = Date.now();
    }
    if( !gameOver){
        requestAnimationFrame(drop);
    }
}

drop();
Max Carroll
  • 4,441
  • 2
  • 31
  • 31
  • Hi @Max, thank you very much for your detailed explanation. These two factors are likely to affect delay. 1. two different variables - dropStart and now 2. requestAnimationFrame Thank you – BBiYak Jun 22 '20 at 11:41
  • Thanks @BBiYak, if you found my answer useful could you vote it up ;) – Max Carroll Jun 22 '20 at 18:41
  • I clicked the upper arrow next to your reply ('this is useful') Is this the vote you said? haha There are so many things I should learn.. – BBiYak Jun 24 '20 at 01:51
  • I think a reputation of 15 is required to vote the answer up, you may be able to click the green tick which accepts the answer though :) – Max Carroll Jun 24 '20 at 08:23
  • @BBiYak It appears you've got enough reputation to vote this answer now – Max Carroll Jun 24 '20 at 17:00
  • 1
    Yest Max! I voted thank you and have a great day : ) – BBiYak Jun 25 '20 at 00:25
0

OK so rom the source code itself I was not able to find the exact code mentioned in this question, and in the question it doesn't give all of the code for how drop is called, from this code I don't see why it wouldn't be instantaneous as there is no setTimeout or anything stopping it, the only delay is in the console.log call.

Anyways, it says in the mozilla documentation that performacne.now and perhaps Date.now are imprecise, to prevent against attacks

A possible workaround is using the AudioContext loop, as mentioned in the Mozilla documentation and discussed briefly at Web Audio Api precise looping in different browsers.

but anyway, Date.now() gives you the current milliseconds, and performance.now is slightly more accurate, yet both are intentionally distorted by the browser