Why this async function blocks the processing? [duplicate] - javascript

This question already has answers here:
Correct way to write a non-blocking function in Node.js
(2 answers)
Closed 4 years ago.
I don't understand how to work with asynchronous functions.
Why does the code below stop the main thread?
async function foo() {
for (;;) {}
}
foo();

The async keyword, and promises in general, don't make synchronous code asynchronous, slow running code fast, or blocking code non-blocking.
async just makes the function return a promise and provides (with the await keyword) a mechanism to interact with other promises as if there were synchronous.
Your function starts a loop, and then just goes around and around.
It doesn't get to the end of the function, which would end the function and resolve the promise it returned.
It doesn't reach an await keyword and pause while it waits for the awaited promise to be resolved.
It just goes around and around.
If you were actually doing something in the loop which was computationally expensive and you wanted to push off into the background, then you could use a Node.js Worker Thread or a browser-based Web Worker to do it.

Putting the async keyword before the function only implies that this is asynchronous function. You need to include the keyword await before the function that you want to actually wait for. Just like this:
async function hashPin(pin){
const hashedPin = await bcrypt.hash(pin, saltRounds);
}
That's just the example from one of my projects (the redundant code has been removed before posting)

Related

How are promises (and async) "asynchronous", exactly? [duplicate]

This question already has answers here:
Are JavaScript Promise asynchronous?
(3 answers)
When does async function actually return a pending promise?
(1 answer)
Do Javascript promises block the stack
(4 answers)
What are asynchronous functions in JavaScript? What is "async" and "await" in JavaScript?
(2 answers)
Closed last year.
Every single example I read about it has code demonstrations that are synchronously executed, with the article writers pretending they're asynchronous.
No example I've seen yet says the code keeps running past the 'asynchronous' promise. If the code kept running while the promise was fulfilled, or the await was taking place, then it could be called asynchonous.
But if the main line of code stops for the promise/await response, then it's simply synchronous.
Can anyone explain this? I had the impression that code ran past the promise/sync function, rather than stopping and 'awaiting' the result to then continue the rest of the code identically to a normal synchronous execution operation.
Promises themselves aren't really asynchronous. They are a pattern to implement working with other things that themselves are asynchronous.
Just like a callback is just a function, we tend to call them 'callbacks' if they get triggered at a later point.
All a Promise really is for is encapsulating the status of an asynchronous operation and let people access the result.
Asterisk: Promises themselves are also a little asynchronous, because they guarantee that the function passed to then() always happens at least in the next tick if the result already arrived.
And await doesn't block the process, it literally pauses the function and lets other things run. Similar to yield, which is also not asynchronous by itself.
Promises register callbacks for further execution when they resolve:
console.log('Beginning');
const test = new Promise(resolve => setTimeout(resolve, 1000));
test.then(() => console.log('Resolved'));
console.log('End');
Now if you think this is synchronous code:
(async function() {
console.log('Beginning');
const test = new Promise(resolve => setTimeout(resolve, 1000));
await test;
console.log('Resolved');
console.log('End');
})();
Well it's not, it's actually an equivalent of:
console.log('Beginning');
const test = new Promise(resolve => setTimeout(resolve, 1000));
test.then(() => {
console.log('Resolved');
console.log('End');
});
Conclusion: when you await a Promise you just use syntactic sugar. Really nice syntactic sugar that prevents callback hell:
The call stack unwinds and frees the event loop with async/await, just like it would with callbacks, making the event loop available for other code execution until the Promise resolves.

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

Essentially, I have a try block in an async function that basically looks like the following:
async function functionName() {
try {
await function1() // each of function 1, 2, and 3 are async functions
await function2()
await function3()
//some more awaits below this point
} catch(err) {
console.log(err)
}
}
Essentially, I'd like to run function1, function2, and function3 asynchronously in relation to each other (AKA have the three of them run at the same time) but I'd like to wait for all of them to finish before continuing the program (so have the set of 3 run synchronously in relation to the rest of the function). I can't just put the code from function2 and function3 inside of function1 for a variety of reasons, so unfortunately that's not an option. Any help much appreciated!
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 isnt my code running asynchronously in javascript? [duplicate]

This question already has answers here:
Correct way to write a non-blocking function in Node.js
(2 answers)
Closed 4 years ago.
I don't understand how to work with asynchronous functions.
Why does the code below stop the main thread?
async function foo() {
for (;;) {}
}
foo();
The async keyword, and promises in general, don't make synchronous code asynchronous, slow running code fast, or blocking code non-blocking.
async just makes the function return a promise and provides (with the await keyword) a mechanism to interact with other promises as if there were synchronous.
Your function starts a loop, and then just goes around and around.
It doesn't get to the end of the function, which would end the function and resolve the promise it returned.
It doesn't reach an await keyword and pause while it waits for the awaited promise to be resolved.
It just goes around and around.
If you were actually doing something in the loop which was computationally expensive and you wanted to push off into the background, then you could use a Node.js Worker Thread or a browser-based Web Worker to do it.
Putting the async keyword before the function only implies that this is asynchronous function. You need to include the keyword await before the function that you want to actually wait for. Just like this:
async function hashPin(pin){
const hashedPin = await bcrypt.hash(pin, saltRounds);
}
That's just the example from one of my projects (the redundant code has been removed before posting)

Javascript - wait for async call to finish before returning from function, without the use of callbacks

I want to preface by saying I've viewed a lot of stackoverflow questions regarding this topic, but I haven't found any 'duplicates' per se since none of them contain solutions that would solve this specific case.
I've mainly looked at How do I return the response from an asynchronous call?, and the section on 'Promises with async/await' would work inside an asynchronous function, but the function I'm working on is not async and is part of an existing codebase that I can't change easily. I wouldn't be able to change the function to async.
The section on callbacks wouldn't work either, which is explained further below. Anyway, I'll jump into my question:
I'm editing a function (standard function, not async) in JavaScript by adding an asynchronous function call. I want to wait until the async call finishes before I return from the function (since the result of the async call needs to be included in the return value). How would I do so?
I looked into using callbacks, which would allow me to write code which is guaranteed to run only after the async call completes. However, this wouldn't interrupt the flow of the program in the original function, and the original function could still return before the callback is run. A callback would allow me to execute something sequentially after the async function, but it wouldn't allow me to wait for asynchronous call to complete at the highest level.
Example code, which wouldn't return the desired result:
function getPlayers() {
... other code ...
let outfieldPlayers = asyncGetOutfieldPlayersCall()
... other code ...
allPlayers.add(outfieldPlayers)
return allPlayers // the returned value may or may not include outfield players
}
The actual problem I'm facing is a little more complicated - I'm calling the async function in each iteration of a for loop, and need to wait until all calls have completed before returning. But, I think if I can solve this simpler problem, I can solve the problem with a for loop.
Sadly, it is pretty much impossible to wait for async code in a synchronous way. This is because there is no threading in JS (most JS runtimes, but some are). So code is either synchronous or asynchronous.
Asynchronous code is possible because of the event loop. The event loop is part of the javascript runtime. It works by keeping a stack of callback functions that run when events trigger them - usually either timeout events (which you can set with setTimeout()) or IO events (which happen when you make disk or HTTP requests, or on user interaction). However, these callbacks only run when no other code is running, so only when the program is idle and all functions have returned.
This means that techniques like "spin loops" (where you just run a loop until a condition is changed by another thread) that work in threaded environments don't work because the async code won't run until the spin loop finishes.
More Info: https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4
If you are using NodeJS, this is possible through execSync.
This requires you to place your asynchronous code in a separate file, spawn a separate process using execSync, which will wait until it exits.
For example, consider the following async function which prints an array.
// task.js
(async function() {
await new Promise((resolve) => setTimeout(() => {
console.log(JSON.stringify([3,4,5]));
resolve();
}, 1000));
})();
Now, you can invoke this from your main process:
function asyncGetOutfieldPlayersCall() {
const execSync = require('child_process').execSync;
return JSON.parse(execSync("node task.js"));
}
function getPlayers() {
let allPlayers = [1,2];
// ... other code ...
let outfieldPlayers = asyncGetOutfieldPlayersCall();
// ... other code ...
allPlayers = allPlayers.concat(outfieldPlayers)
return allPlayers;
}

Understanding Async/Await patterns in JavaScript

I'm relatively new to JavaScript programming, and so callbacks have been giving me trouble. I'm using a framework that supports the "async/await" syntax from ES7 (Meteor), but I'm having some difficulty understanding exactly how I can implement an asynchronous function that calls other functions.
What I want to do: The user enters a URL, data is fetched from the URL, processed, and put into a database. I want this to occur in a non-blocking manner, so that the user can continue to use the application while this process is occurring.
Pseudocode:
async function foo(URL) {
try {
//using request-promise npm package to make the request
const data = await makeRequestPromise(URL)
const parsedData = await myParsingFunciton(data);
MyDB.insert({
parsedData,
});
catch (err) {
console.log(err);
}
So I have a few questions:
Is anything that happens in the scope of this async function non-blocking?
If so, can I just use a series of synchornous functions since I can't parse the data before I receive it anyway?
What happens if I try to await a function that is not defined as asynchronous (for example myParsingFunction)? My research seems to imply that the function is forced to return a promise, but I'm not certain how I would determine that. Doing so in the code does not return an error, but JavaScript seems surprisingly tolerant of weirdness with regards to returns.
I would like to add that my function works and things go into the database, but I have no idea how to test if it is actually non-blocking.
Is anything that happens in the scope of this async function non-blocking?
It's non-blocking in the sense that the call to foo won't stall the thread until all the work is done, because foo is an asynchronous function calling at least one other asynchronous function. There's only one main UI thread on browsers (and one thread in NodeJS), so unless you use web workers in the browser, the asynchronous code will at some point be occupying that thread (e.g., blocking). But the asynchronous functions you call within foo won't block the thread within foo; instead, foo returns a promise behind the scenes that gets resolved eventually after all the async work is done. (That's why it's an asynchronous function.)
If so, can I just use a series of synchornous functions since I can't parse the data before I receive it anyway?
Not quite following this question. Your code looks fine. It looks synchronous, but it isn't, assuming one or more of the functions you're calling is asynchronous.
What happens if I try to await a function that is not defined as asynchronous (for example myParsingFunction)?
It makes your call to that function asynchronous (even though the function isn't) but then the resolution happens as soon as possible thereafter; the resolution value is the value returned by the function. You can see that in action with this quick experiment:
// `foo` is an asynchronous function, and so calling it returns a promise
async function foo() {
// We haven't awaited anything yet, so this is run synchronously when we
// call `foo`
console.log("A");
// `Math.random` is, of course, a synchronous function; but we *call* it
// asynchronously since we've used `await`
let data = await Math.random();
// Which means this line doesn't run until later, after `foo` has already
// returned its promise
console.log("B");
}
// When we call `foo`, the synchronous part runs first and it returns its
// promise (which we're not using)
foo();
// And then this line runs, BEFORE the asynchronous part of `foo` can run
console.log("C");
// ...and so we see A, C, B; without the `await` on the call to
// `Math.random`, we'd see A, B, C
It may (or may not!) be useful to remember that async/await is purely syntactic sugar for interacting with promises. async means the function returns a promise. await means you're waiting (asynchronously) for a promise resolution.
E.g.:
async function foo() {
return 42;
}
is sugar for
function foo() {
return new Promise(resolve => {
resolve(42);
});
}
and sugar for
let data = await something();
// ...do somthing...
is
something().then(data => {
// ...do something...
});
leaving aside some minor details.

Categories

Resources