Call an Asynchronous JavaScript Function Synchronously

Call An Asynchronous Javascript Function Synchronously

"don't tell me about how I should just do it "the right way" or whatever"

OK. but you should really do it the right way... or whatever

" I need a concrete example of how to make it block ... WITHOUT freezing the UI. If such a thing is possible in JS."

No, it is impossible to block the running JavaScript without blocking the UI.

Given the lack of information, it's tough to offer a solution, but one option may be to have the calling function do some polling to check a global variable, then have the callback set data to the global.

function doSomething() {

// callback sets the received data to a global var
function callBack(d) {
window.data = d;
}
// start the async
myAsynchronousCall(param1, callBack);

}

// start the function
doSomething();

// make sure the global is clear
window.data = null

// start polling at an interval until the data is found at the global
var intvl = setInterval(function() {
if (window.data) {
clearInterval(intvl);
console.log(data);
}
}, 100);

All of this assumes that you can modify doSomething(). I don't know if that's in the cards.

If it can be modified, then I don't know why you wouldn't just pass a callback to doSomething() to be called from the other callback, but I better stop before I get into trouble. ;)


Oh, what the heck. You gave an example that suggests it can be done correctly, so I'm going to show that solution...

function doSomething( func ) {

function callBack(d) {
func( d );
}

myAsynchronousCall(param1, callBack);

}

doSomething(function(data) {
console.log(data);
});

Because your example includes a callback that is passed to the async call, the right way would be to pass a function to doSomething() to be invoked from the callback.

Of course if that's the only thing the callback is doing, you'd just pass func directly...

myAsynchronousCall(param1, func);

How to await an async call in JavaScript in a synchronous function?

but the problem is - await is only allowed in async-methods.

Exactly, and no, there's no workaround for that. JavaScript's run-to-completion semantics demand that synchronous functions complete before any pending asynchronous action (such as the callback to an XHR handler for an async XHR call) can run.

The way JavaScript runs on a given thread is that it processes a queue of jobs1:

  1. Pick up the next pending job
  2. Synchronously execute the code for that job
  3. Only when that job completes go back to Step 1 to pick up the next job

(It's a bit more complicated than that, there are two levels to it, but that's not relevant to this particular question.)

XHR completions and such are jobs that get scheduled in the queue. There is no way to pause a job, run another job from the queue, and then pick up the paused job. async/await provides dramatically simpler syntax for handling asynchronous operations, but they don't change the nature of the job queue.

The only solution I see for your situation is to go async all the way to the top level. This may not be as complicated as you might think (or maybe it will be). In many cases it's adding async in front of function on a lot of functions. However, making those functions asynchronous is likely to have significant knock-on effects (for instance, something that was synchronous in an event handler becoming asynchronous changes the timing of what happens in relation to the UI).

For example, consider this synchronous code:

var btn = document.getElementById("btn");

btn.addEventListener("click", handler, false);

function handler(e) {
console.log("handler triggered");
doSomething();
console.log("handler done");
}

function doSomething() {
doThis();
doThat();
doTheOther();
}

function doThis() {
console.log("doThis - start & end");
}
function doThat() {
console.log("doThat - start");
// do something that takes a while
var stop = Date.now() + 1000;
while (Date.now() < stop) {
// wait
}
console.log("doThat - end");
}
function doTheOther() {
console.log("doThat - start & end");
}
.as-console.wrapper {
max-height: 80% !important;
}
<input type="button" id="btn" value="Click Me">
<p id="text"></p>

Running multiple functions asynchronously in relation to each other but synchronously in relation to program as a whole

Assuming all your functions return promises that resolve/reject when the asynchronous operations are done, then you can use Promise.all() to let them all be in-flight at the same time and be notified when they are all done:

async function functionName() {
try {
let results = await Promise.all([function1(), function2(), function3()]); //some more awaits below this point
} catch(err) {
console.log(err)
}
}

Or, if you don't want the short-circuit if there's an error, you can use Promise.allSettled() instead and it will notify you only when all requests are done, regardless of whether any of them had an error.

Keep in mind that only truly non-blocking, asynchronous operations in your functions will actually run in parallel. Any blocking, synchronous code in your functions will still only run one at a time. And, keep in mind that just because a function is tagged as async does not make anything run asynchronously. All the async keyword does is allow you to use await inside the function and make the function automatically return a promise. It does not make anything in the function run asynchronously.

If you showed your real code rather than pseudo-code, we could comment more specifically about exactly what you're doing and the best way to code it. Please resist the temptation to post questions with only pseudo-code. We can always help better when we see your real code.


Also, none of this runs synchronously with regard to the program as a whole. It will appear to run synchronously within the body of the function (as the function execution will be suspended by the await). But, as soon as the function hits the await, it immediately returns an unresolved promise and execution after this function call continues. The only way to run someting synchronously with regard to the program as a whole is to use synchronous coding, not non-blocking, asynchronous coding.

Why is this async function is running synchronously?

Setting something as async will wrap the return object into a Promise. Promises are used to deal with asynchronous behavior, but there's nothing inherently asynchronous about the content of the test function. If instead you were to wrap the contents into a setTimeout function, that would cause a delay which would mimic asynchronous behavior and match the outcome you were expecting.

async function test() {  setTimeout(() => {    for(let i = 0; i < 2; i++){        console.log("test");    }  })}
console.log("a");test();console.log("b")

how to make an asynchronous javascript function synchronous

for others that will be in the same situation as I am, here is the solution.

first step, I made the captcha function to return a promise

function captcha() {
return new Promise(function(resolve, reject) {
grecaptcha.ready(function() {
grecaptcha.execute(recaptcha_site_key, {action: 'run'}).then(function(token) {
resolve(token);
});
});
});
}

second step, async/await for the variable to become available

async function run() {
let g_recaptcha_response = await captcha();
document.forms['params'].elements['g_recaptcha_response'].value = g_recaptcha_response;
let data = input();
data = confirm(data);
if (data['error'] === true) {
return data;
}
let url = `${origin}/app/json`;
data = request(url, data);
// note: preparing for input / next request.
document.forms['params'].elements['token_id'].value = data['token_id'];
return data;
}

third step, create an IIFE at the top-level

(async function(){ let response = await run(); })();

How to wrap async function calls into a sync function in Node.js or Javascript?

deasync turns async function into sync, implemented with a blocking mechanism by calling Node.js event loop at JavaScript layer. As a result, deasync only blocks subsequent code from running without blocking entire thread, nor incuring busy wait. With this module, here is the answer to the jsFiddle challenge:

function AnticipatedSyncFunction(){
var ret;
setTimeout(function(){
ret = "hello";
},3000);
while(ret === undefined) {
require('deasync').runLoopOnce();
}
return ret;
}

var output = AnticipatedSyncFunction();
//expected: output=hello (after waiting for 3 sec)
console.log("output="+output);
//actual: output=hello (after waiting for 3 sec)

(disclaimer: I am the co-author of deasync. The module was created after posting this question and found no workable proposal.)

Async function return inside synchronous function

Does the fetchAndDecode() function get pushed to the async even queue

No. It's synchronous. It just calls a function (fetch) which triggers something asynchronous.

Why wrap this async code inside a sync declaration? Why wrap it at all?

It takes two arguments. It lets you reuse the function when those arguments change without duplicating the entire body.

Would it be more correct to declare

No, that's just more verbose.

await is useful when you want to pause a function until a promise resolves and then do something with the resolved value inside that function.

You aren't doing that. You're just returning.

"Return the promise returned from fetch" is a lot simpler than "Create a new promise (and return it). Wait for the promise returned from fetch to resolve, get its value, then resolve the first promise with that value."



Related Topics



Leave a reply



Submit