0

Do async functions parameter references get affected by synchronous code execution?

To be more specific I am creating a little grid animation using an array of custom <Tile/>. Then in another function I am creating an array animation that holds "Keyframes" (I use the term loosely). Basically each index is an array of which <Tile/>s are changed in each "frame".

Then I have a Render function that takes that array of "keyframes" and renders them as follows:

// Returns a Promise that resolves after "ms" Milliseconds
const timer = (ms) => new Promise((res) => setTimeout(res, ms));

//Renders gameboard tile by tile with given ms delay
async function render(animation) {
  
  for (var i = 0; i < animation.length; i++) {
    
    //do some rendering stuffs

    await timer(3000 / animation.length); // This *Should* ensure 3s of total animation time
  }
}

Now the question is if I were to add a "stopper" to this function in a way like:

//Renders gameboard tile by tile with given ms delay
async function render(animation, stop) {
  
  for (var i = 0; i < animation.length; i++) {
    if(stop){
       //stop rendering
    }
    //do some rendering stuffs

    await timer(3000 / animation.length); // This *Should* ensure 3s of total animation time
  }
}

Lets say I call render multiple times.

If I were to create a synchronous way to change the value of stop to true: Would it then pause the asynchronous stack of render calls, update stop, then resume the render calls only to then exit because of the conditional? OR am I just mistaken and would the render calls simply not run at all because SOME kind of synchronous code would have to be executing in order to change the value of stop synchronously and in the scope of the async calls to render stop would HAVE to be false in order for the synchronous code to be finished and the async stack to start.

Nate Baker
  • 17
  • 4
  • 1
    "*If I were to create a synchronous way to change the value of `stop` to true*" - **how** would you do that? Notice that in multiple calls to `render`, you'd have multiple `stop` variables, each in its own scope. – Bergi Sep 26 '22 at 15:50
  • if stop is a boolean no, the value is passed as a copy. if you pass an object however currentAnimation = {stop: false}; And change the value of stop during the animation, you will reach your stop condition – user3252327 Sep 26 '22 at 15:52
  • @Bergi @user3252327 THAT was something I had wondered, if ```stop``` would be a reference to the value outside the ```render``` function or if it was "copied" per se and dealt with locally within the ```render``` function call – Nate Baker Sep 26 '22 at 16:04
  • 1
    @NateBaker There's nothing special about `async` functions. [JavaScript is always pass-by-value](https://stackoverflow.com/q/518000/1048572). Does that answer your question or is there still an open question? – Bergi Sep 26 '22 at 16:05
  • @Bergi This was kind of a two-part question: 1 - about exactly what you answered, and 2 - how to go about doing this a "better" way. which the latter was solved by code sprit. But nonetheless thank you! – Nate Baker Sep 26 '22 at 16:11
  • 1
    The "better" way would be to pass an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) as a cancellation token to `render`, and to forward it to `timer`, so that you could `clearTimeout` when the signal is fired. – Bergi Sep 26 '22 at 16:16
  • @Bergi Ooo I'll have to look into that, I'm unfamilliar – Nate Baker Sep 26 '22 at 16:28

1 Answers1

0

Check for is stopped after promise of previous item is resolved.

let stopped = false;

function isStopped() {
  return stopped;
}

function stop() {
  stopped = true;
}

function renderItems(items) {
  return items.reduce((promise, item) => {
    return promise.then(() => {
      // Checks if stopped after each promis resolves in order
      if (!isStopped()) {
      // Run next render callback
      return asyncRenderItem(item);
    } else {
      // Dont run next
      return;
    }
    });

  }, Promise.resolve());
}

async function asyncRenderItem(item) { ... }
Code Spirit
  • 3,992
  • 4
  • 23
  • 34
  • 1
    "*note that your for loop wont wait for the await and will run all callbacks at once*" - no, of course it will wait! That's the whole point of `await` syntax. – Bergi Sep 26 '22 at 15:53
  • Sry my mistake, ill edit it but the solution should work nonetheless. – Code Spirit Sep 26 '22 at 15:54
  • Gotcha, so your thought is to, instead of trying to synchronously call ```render``` and change the value of ```stop``` you would just make the entire render process async and stop the headache. And this is why we go to stack overflow :D. I'll try it out and see how it works out, thank you! This was both a question of how references of variables are passed into the async stack as well as asking for guidance on a project. – Nate Baker Sep 26 '22 at 16:08