1

I've been doing a simple program, which simulates someone throwing an object. Everything appears to work, but... I want to execute one loop per ~100ms.

button.addEventListener("click", function(){

  for(let i = bob_x; i < 1504; i++){
    setTimeout(function(){
      pos_x = i;
      //console.log("vx: " + vx);
      //console.log("vy: " + vy);
      //console.log("i: " + i);
      //console.log("G: " + G);
      pos_y = vy/vx*i - G*i*i/2/vx/vx;

      obj.style.setProperty("left", pos_x);
      obj.style.setProperty("top", parseInt(pos_y, 10));
    }, 100)
  }
})

It doesnt wait and executes everything in about quarter a second. I dunno why.

vx and vy here are coordinates of a vector, made by subtracting coordinates from eventlistener "mouseup" from coordinates from event "mousedown". Bob_x is the x-coordinate of a block representing a guy.

Filburt
  • 17,626
  • 12
  • 64
  • 115
Embid123
  • 467
  • 5
  • 17
  • 1
    You should look into [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). –  Oct 09 '18 at 07:15

2 Answers2

3

It doesnt wait and executes everything in about quarter a second.

A tenth, actuually (100ms).

The main problem is that you're scheduling a bunch of timers that will all go off 100ms later. If you want them at 100ms intervals, you need to extend the 100ms timeout for subsequent timers, for instance by multiplying 100 by i - bob_x + 1:

button.addEventListener("click", function(){

  for(let i = bob_x; i < 1504; i++){
    setTimeout(function(){
      // ...
    }, 100 * (i - bob_x + 1)) // <============
  }
})

Separately, it seems odd that pos_x and pos_y aren't declared within the handler.

If this is for animation purposes, you probably want to use requestAnimationFrame for this. Here's an article by Paul Irish that may be useful.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I wanted to say, that instead delaying each iteration by a tenth of a second, it executes whole code by about a quarter. – Embid123 Oct 09 '18 at 07:22
2

Your for loop is running synchronously, setting a bunch of timeouts, each of which will occur 100 ms after the for loop ends. If you want to wait for each function to finish before going on to the next iteration, you'll need a different strategy, perhaps await a delay on every iteration:

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
button.addEventListener("click", async function(){

  for(let i = bob_x; i < 1504; i++){
    await delay(100);
    pos_x = i;
    //console.log("vx: " + vx);
    //console.log("vy: " + vy);
    //console.log("i: " + i);
    //console.log("G: " + G);
    pos_y = vy/vx*i - G*i*i/2/vx/vx;

    obj.style.setProperty("left", pos_x);
    obj.style.setProperty("top", parseInt(pos_y, 10));
  }
})
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Actually, your `delay` obviously never rejects, and so there isn't much difference between this `async` function and their existing handler (which also doesn't handle errors). I'm always leery of returning promises to things that don't expect them, but the event system completely ignores the return value of a handler added by `addEventListener`, so... – T.J. Crowder Oct 09 '18 at 07:29