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:
- Pick up the next pending job
- Synchronously execute the code for that job
- 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
Pass Props to Parent Component in React.Js
Jquery How to Bind Onclick Event to Dynamically Added HTML Element
How to Submit a Form Using JavaScript
When to Use Vanilla JavaScript VS. Jquery
Read Environment Variables in Node.Js
Cross Browser JavaScript (Not Jquery...) Scroll to Top Animation
Pass a Parameter to a Content Script Injected Using Chrome.Tabs.Executescript()
How to Replace While Loops with a Functional Programming Alternative Without Tail Call Optimization
How to Redirect with JavaScript
Warn User Before Leaving Web Page with Unsaved Changes
Is Right Click a JavaScript Event
JavaScript Setinterval and 'This' Solution
Reactjs - Does Render Get Called Any Time "Setstate" Is Called
Does React Keep the Order for State Updates
Find Out Whether Chrome Console Is Open
Accessing Jpeg Exif Rotation Data in JavaScript on the Client Side