1

I'm pretty new to all this stuff and have a few questions regarding async and callbacks within Nodejs/js.

I have the following fiddle setup: https://jsfiddle.net/JimmyJoe12378/38nkcuhL/17/

function updateTestVariable(key, callback) {
  console.log("2 ENTERupdateTestVariable key is: " + key);
  callback(key)
}

var testVariable = ""

console.log("1 BEFORE updateTestVariable is called testVariable is " + testVariable)

updateTestVariable("VARIABLE HAS UPDATED", async function(firstParam) {
  console.log("3 ENTER updateTestVariable firstParam is: " + firstParam);
  console.log("4 text before timeout starts testVariable is: " + testVariable)

  var mockingAsyncServiceCall = await setTimeout(() => {
    testVariable = firstParam
    console.log("5 AFTER TIMEOUT COMPLETE  testVariable is " + testVariable)
  }, 4000);

  console.log("6 line after timeout, testVariable is " + testVariable)
})

console.log("7 AFTER updateTestVariable is called testVariable is " + testVariable)

Essentially what I want to do is call a function, in this case called "updateTestVariable" which accepts a key and a callback function.

I have a variable declared before the updateTestVariable function is called (which is called testVariable). In the callback function passed into updateTestVariable I have tried to mock an Async Service call which would update the variable. I'm using the setTimeout() function for this (I'm not sure if this is a correct representation of this or not). I have numbered the log statements in the fiddle for easy reference.

Anyway, below you can see the order my logs print out.

The desired output would be for line 6 to wait until the mockAsyncServiceCall was complete and to print out after line 5 with the variable populated.

Additionally, I'm not sure if it is possible since its outside the function but I'm just curious if it is also possible to get line 7 to print out after line 6. Something to point out is the updateTestVariable function is not marked as async and thats not something that I want to change otherwise I suspect I could use async/await?

As mentioned above, I'm not sure if my use of the setTimeout function is actually a correct mimic of an async service call or not but was just something I was trying out.

"1 BEFORE updateTestVariable is called testVariable is "
"2 ENTERupdateTestVariable key is: VARIABLE HAS UPDATED"
"3 ENTER updateTestVariable firstParam is: VARIABLE HAS UPDATED"
"4 text before timeout starts testVariable is: "
"7 AFTER updateTestVariable is called testVariable is "
"6 line after timeout, testVariable is "
"5 AFTER TIMEOUT COMPLETE  testVariable is VARIABLE HAS UPDATED"

Any help is greatly appreciated, Thank you.

Nick Parsons
  • 45,728
  • 6
  • 46
  • 64
J145
  • 607
  • 1
  • 11
  • 16
  • 1
    `await setTimeout` always returns a number immediately. You need to wrap that in a `Promise`. – InSync Apr 23 '23 at 12:31
  • 1
    `await` really only makes sense to use on a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) (or thenable). See this on how you can correctly "mock" your async call that returns a promise: [What is the JavaScript version of sleep()?](https://stackoverflow.com/a/39914235). – Nick Parsons Apr 23 '23 at 12:33
  • What's the point of `updateTestVariable` accepting a callback in the first place? – Bergi Apr 23 '23 at 12:46

1 Answers1

3

To make 5 come after 4, consider wraping the setTimeout() in a Promise. This allows the callback to properly "wait" for the setTimeout() to resolve, before 6 is then called.

For 7 to come last, making return the callback's call result in updateTestVariable() so that updateTestVariable() would then return a Promise, whereby we can use .then() to log 7 only after updateTestVariable() is completely resolved.

function updateTestVariable(key, callback) {
  console.log("2 ENTERupdateTestVariable key is: " + key);
  return callback(key)
}

var testVariable = ""

console.log("1 BEFORE updateTestVariable is called testVariable is " + testVariable)

updateTestVariable("VARIABLE HAS UPDATED", async function(firstParam) {
  console.log("3 ENTER updateTestVariable firstParam is: " + firstParam);
  console.log("4 text before timeout starts testVariable is: " + testVariable)

  var mockingAsyncServiceCall = await new Promise((resolve) => {
    setTimeout(() => {
      testVariable = firstParam
      console.log("5 AFTER TIMEOUT COMPLETE  testVariable is " + testVariable);
      resolve();
    }, 4000);
  });

  console.log("6 line after timeout, testVariable is " + testVariable);
}).then(() => console.log("7 AFTER updateTestVariable is called testVariable is " + testVariable));
Wongjn
  • 8,544
  • 2
  • 8
  • 24
  • 2
    Note that OP did mention that they wanted to avoid changing `updateTestVariable` to be async, which you can still do to get the correct behaviour by just changing it to `return callback(key)` – Nick Parsons Apr 23 '23 at 12:37
  • Thank you very much. This is very useful. Appreciate your help. – J145 Apr 23 '23 at 13:10