0

I know one must not block the loop, I know use call backs, and I know ES6 await. The more I research this the more it reaffirms it.

But sometimes your hands are tied. Is there a way to tell JavaScript, please go check on your event queue, and service those, then come back here before continuing execution.

Something like inspired by the MDN docs:

if (queue.hasNextMessage()) {
  queue.processNextMessage()
}

There are similar threads about use datetime to wait a duration, but I don't know how the long other event thread will take, been looking at polling the promise status, but it appears to be a dead end.

The context is I have to override a validation callback. The caller of the callback does not wait for a promise to resolve (That I cant change).

Here is the test setup showing the concept. I have made a few attempts, but none of them work because they are always stuck in the main loop.

// The validate function depends on a fetch call which takes time.
// Free to change this.
function validate() {
    return fetch(url).then(response => response.json())
        .then(data => {console.log(data); return true;})
        .catch(msg => {console.log(msg); return false;})
}

// Cannot change this function, I am not in control of it
function CallValidate() {
    console.log("Validation Result: ", Boolean(validate()));
}

// This is the setup for when test passes
let url = 'http://api.open-notify.org/astros.json';
CallValidate();

// This is the setup for when test fails
// This currently fails because the promise objects is being evaluated
// to true, instead of waiting for its response.
url = 'http://DUMMY.NOT.WORKING.URL';
CallValidate();
run_the_race
  • 1,344
  • 2
  • 36
  • 62
  • 2
    No, there is not. – Pointy Jul 17 '20 at 14:16
  • Does this answer your question? [What is the JavaScript version of sleep()?](https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep) While some of the answers discuss ES6+ solutions, you can find the answer to this question. – Heretic Monkey Jul 17 '20 at 14:27
  • Yes if you know what you are waiting for to be handled you can use `promiseOfTheThingYouAreWaitingFor.then(value => {/* code */})` – 3limin4t0r Jul 17 '20 at 14:37
  • @3limin4t0r yes that is using a call back. The problem is I am overiding a callback that will not wait for a promise to be fufilled before returning. – run_the_race Jul 17 '20 at 15:06
  • @run_the_race It sounds like you need to make it wait for the promise then. Could you add some code of what you are actually trying to achieve? – 3limin4t0r Jul 17 '20 at 15:33
  • @3limin4t0r I added some code I have been working with to illustrate it (I cut out all the failed attempts and dead ends). – run_the_race Jul 17 '20 at 15:50

2 Answers2

0

Is there a way to tell JavaScript, please go check on your event queue, and service those, then come back here before continuing execution.

No, but you can do something very similar: divide your computation into several tasks. In Node.js, you can use setImmediate() to queue a task. In the browser, you can use messages, as outlined by this answer.

Example:

function setImmediate(callback) {
  const channel = new MessageChannel();
  channel.port1.onmessage = () => {
    callback();
  };
  channel.port2.postMessage("");
}

console.log("Task 1");
setImmediate( () => {
  console.log("Task 2");
});
D. Pardal
  • 6,173
  • 1
  • 17
  • 37
  • Thanks, that `await` looks like a gotcha (not ES5) , but I don't fully understand if I can get around it, busy researching MessageChannel now. – run_the_race Jul 17 '20 at 14:43
  • Thanks for the change. From what I can see, The channel object can have calls backs attached to it when it receives a message. This does not block the current thread. Fair enough you did prefix your answer with "No". If one could wait for a message to arrive, and while waiting the receiver was free to execute in the main loop, then this would help. – run_the_race Jul 17 '20 at 15:07
0

Boolean(validate()) will always evaluate to true, because validate returns a Promise which is a truthy value no matter what it resolves to.

If you can't change CallValidate, you might still be able to lift up the fetch call. But I'm not sure if that's an option for you.

async function validateUrl(url) {
  const valid = await fetch(url).then(response => response.json())
    .then(data => {console.log(data); return true;})
    .catch(msg => {console.log(msg); return false;});

  function validate() {
    return valid;
  }

  function CallValidate() {
    console.log("Validation Result: ", Boolean(validate()));
  }

  CallValidate();
}

// assuming you are in async function context
await validateUrl('http://api.open-notify.org/astros.json');
await validateUrl('http://DUMMY.NOT.WORKING.URL');

If moving the function is also no option I would ditch the CallValidate code and either write something yourself, or pick another library/helper/etc that does handle asynchronous functions (with promise return values).

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52