1
var td = {
setTimeout: function(callback, ms){
var dt = new Date();
    var i = dt.getTime(), future = i+ms;
    while(i<=future){
      if(i === future){
        callback();
      }
      // i = dt.getTime();
      i++;
  }
 }
};
td.setTimeout(function(){
    console.log("Hello"); // executes immediately
}, 3000);

The problem with this approach is that, at the end of the while block I am setting the value of i to i + 1 which I think, should be set to the current timestamp (dt.getTime()), that way, future (a timestamp value at which the callback function should execute) can be compared with the current timestamp, which is the value of i.

But when I comment out i++ and uncomment this line:

i = dt.getTime();

and run the script, the browser freezes. Is there a way to create a setTimout() method that would serve the same purpose as window.setTimeout()?

Tanmay
  • 3,009
  • 9
  • 53
  • 83
  • 1
    It's is not really possible to simulate `setTimeout` in user land code because JavaScript doesn't expose any APIs to directly add functions to the event queue. Anyways... what's actually your question? – Felix Kling Jun 11 '17 at 15:54
  • 1
    You should understand that even if you fix the endless loop issue, the browser will still lock up. That's because the loop will prevent anything else from being executed until it terminates. – Felix Kling Jun 11 '17 at 16:05
  • Take a look at [**this answer**](https://stackoverflow.com/a/41814108/6647153) of a more-or-less simillar question. – ibrahim mahrir Jun 11 '17 at 16:21

2 Answers2

1

The problem with your code is, that dt.getTime() always returns the same value (namely the time when the dt object was created. To make this working, you need to do

dt = new Date();

before you set

i = dt.getTime();
Maurice
  • 346
  • 2
  • 6
  • That is exactly what he is doing. – ibrahim mahrir Jun 11 '17 at 15:59
  • @ibrahimmahrir: no, not in the loop. – Felix Kling Jun 11 '17 at 16:00
  • He is only doing it once as he calls setTimeout.. So the break condition does not change and he stays in an endless loop – Maurice Jun 11 '17 at 16:01
  • 2
    One of the reasons why I rather use `Date.now()`... no reason to hold on to date objects. – Felix Kling Jun 11 '17 at 16:01
  • @ibrahimmahrir: if they want to get the *current time* in each iteration then they have to do that. – Felix Kling Jun 11 '17 at 16:03
  • @ibrahimmahrir there is a point of doing it! He is checking for "while(i<=future)" so if i does not change he will not exit the loop (or enter the if clause) – Maurice Jun 11 '17 at 16:04
  • @FelixKling @MauriceA that's what `i++` does. We are arguing wether `i` should be incremented or should it be now's exact time. Either way it won't work as expected, the `dt.getTime()` inside the loop will halt the loop for probably a long time (could be more than a second thus freezing the browser), the `i++` will increment `i` faster thus giving the illusion of immediate execution of the callback. – ibrahim mahrir Jun 11 '17 at 16:08
  • 1
    @ibrahimmahrir: you are mostly right. But `dt.getTime()` holds the loop *forever*! Imagine it returns `5`. Then `i++` makes it `6`. In the next iteration `i = dt.getTime()` resets it to `5`... `i` never *really* increases. Getting the current time would at least fix the infinite loop. But as you can see from my comments on the question, I already pointed out that this is not the right approach. – Felix Kling Jun 11 '17 at 16:11
  • @FelixKling Yeah! Absolutly correct. I'm talking about the whole concept of either `i++` or `i = now's time` which both won't work. – ibrahim mahrir Jun 11 '17 at 16:13
  • @FelixKling This reminded me of my [**silly question**](https://stackoverflow.com/q/41814068/6647153) a while back. – ibrahim mahrir Jun 11 '17 at 16:14
  • 1
    @ibrahimmahrir I imagine everybody encounters something like this at least once when venturing into the mysterious lands of JavaScript ;) – Felix Kling Jun 11 '17 at 16:18
  • @FelixKling @MauriceA @ibrahimmahrir: Okay, even if I use `Date.now()` instead of `getTime()`, the browser still freezes for the amount of time (milliseconds) passed in the second argument of the `setTimeout()` method. Yes, unlike `getTime()` method, `Date.now()` doesn't hold the loop forever, but I need to know a. Why is the browser freezing? b. Is there any way to get rid of this freezing? – Tanmay Jun 11 '17 at 16:40
  • I'm not a JavaScript pro, but I think that your timeout functions runs on the main UI thread and blocks everything while running.. Take a look at JavaScript promises to try to do your call asynchronous. – Maurice Jun 11 '17 at 16:51
  • @MauriceA. No, promises won't help here either. Asynchronous functions can only be created using native implementation, and `window.setTimeout` is the way to go here – Bergi Jun 11 '17 at 17:39
  • @Eisenheim: Which is exactly what I tried to explain in my comments to your question. *"Is there any way to get rid of this freezing?"*. Use `setTimeout` :) – Felix Kling Jun 11 '17 at 17:53
  • @Bergi I think elaborating `native implementation` would be helpful for me to understand what's going on here. Because from a programmer's standpoint I would argue that standard built-in objects/methods in a programming language are written from scratch using the same language. I mean if I can implement my own forEach(), filter(), map() etc., why not setTimeout()? If this is a UI-thread issue, how did the people who first wrote `window.setTimeout()` deal with it? What magic have they put into it that makes it NOT freeze the browser window? – Tanmay Jun 11 '17 at 19:16
  • @Eisenheim No, some builtins need access to the lower lever implementation. Only helper functions can be implemented by only using the language itself (sans optimisations) - like `Array`, `JSON`, `RegExp` or `Date` methods. But things like object construction, `Object.getPrototypeOf`, `Date.now`, native operators (keywords), `eval`, and more *do* need to be native. Asynchrony is just yet another of those magic things. – Bergi Jun 11 '17 at 19:47
0

Behold.. setTimeout that isn't synchronous >:D

function timeout(fn,n){
  (async()=>{
    n=n||0; var time=Date.now()+n
    await new Promise(r=>r()) //asynchronous even if n is 0
    while(Date.now()<time){
      await new Promise(r=>r())
    }
    fn()
  })()
  return true
}

//demonstration
timeout(()=>console.log(3),200)
timeout(()=>console.log(2),20)
console.log(1)
The Bomb Squad
  • 4,192
  • 1
  • 9
  • 17