Async callback for EventEmitter - javascript

Is it possible to do provide an async callback to an EventEmitter in TypeScript or JavaScript?
someEmitter.on("anEvent", async () => console.log("hello"));
Will this cause the function to be run asynchronously? If so, why would one ever not use an async function on an EventEmitter?

Is it possible to do provide an async callback to an EventEmitter in TypeScript or JavaScript?
Yes, you can provide an async function to an eventEmitter and that will allow you to use await inside the callback, but it does not magically make your function run asynchronously.
It also will not change anything outside of your callback function. The eventEmitter will call your callback when the event occurs. Your callback will end up returning a promise that the eventEmitter object will not do anything with.
So, you can do it in order to use await inside your callback function (for your own internal reasons), but it doesn't change anything else outside the callback. It doesn't change how the eventEmitter does the rest of its business in any way.
Will this cause the function to be run asynchronously?
No. It doesn't change how your function is called. If your function consists entirely of synchronous code, it will still be called and run synchronously.
FYI, this is true for any function declared async. That does not change how the function is called in any way. It changes a few things that you can do inside the function and it forces the function to return a promise, but it doesn't change how the function is called. Synchronous code is still synchronous code whether its in an async function or a regular function. I'd really suggest you read a lot more about what an async function actually is.

Related

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.

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;
}

Why do async functions return promise of values not values directly?

I now understand that async functions return promises of values not values directly. But what I don't understand is what the point of doing that in the first place. As far as I understand, async functions are used to synchronize code inside them, now after we got the value from a promise using the await statement inside the async function, why should we return another promise? Why don't we just return the result directly or return void?
async functions are used to synchronize code inside them
They aren't. async functions provide syntactic sugar for promises, thus eliminating the need to use callbacks. async function acts exactly like regular function that returns a promise.
There's no way how the result can be returned synchronously from asynchronous function.
If the result should be returned from async function, it should be called and awaited inside another async function, and so on - possibly up to application entry point.
Because you can't know when the asynchronous call will be done. So it just returns a promise to let you make your rest logic with asynchronous call by making then-s chain.
Yes, async function are used to sequentialise the code inside them. They do not - cannot - stop the code execution outside of them. As you probably remember, blocking is bad. You cannot get the result from the future of course, but you don't want to stop the world just to wait for that function to finish either. And that's why when you call such a function, you get back a promise that you either await, or can schedule a callback on and do other things while it waits.

Javascript callback function and an argument in the callback. How must it be used based on the code snippet provided?

I'm reading over a legacy codebase and I ran into this following code:
andThenWe: function(callback) {
var qunitAssertAsync = new window.AssertAsync(callback);
return qunitAssertAsync;
},
and here's the call site:
andThenWe(function(done) {
...(some code)
done();
});
So in the call site, we're passing in an anonymous function which will then be === 'callback' right? However, this callback has an argument called done and seems to be called at the end of this function. That argument is kind of like a block parameter in Ruby right? So somewhere in the window.assertAsync the callback MUST be called and passed some kind of arugment which is probably === to Qunit's assert.async right? (most likely). The details of the window.assertAsync are really complicated so I just want to understand at a high level what must be going on. Am I making proper assumptions?
This is all possible because callback in the function signature is an anonymous function that be invoked at a later time right? Also done itself in the callback function must be a function itself at runtime right?
I think this is an attempt to make qunit.async more "readable" (haha).
qunit.async is used to force tests to wait until an async operation has completed before exiting the test.
The done callback must be invoked when the writer of the test knows everything async has completed.

How to rewrite this asynchronous method to return the value synchronously?

There are many questions on making a Nodejs/Javascript method synchronous, but the answers I have seen so far involved using libraries such as async and fibrous.
But to use libraries such as fibrous, I have to wrap my function with their wrapper.
I am seeking a solution where the code lies within my function (not outside and wrapping it).
For example, this is my async function which uses a callback:
function myFunc(callback) {
// Classic database fetch which is asynchronous
db.find("foo", function(err, results) {
callback(err, results);
});
}
What I want is for the function to return the results:
function myFunc() {
// Make this function synchronous, and return the result
// ...
return results;
}
How do I do that?
Once again, I don't want to wrap myFunc with other functions. I am thinking if a sleep loop works?
No, you can't use a loop to wait for an asynchronous call. Javascript is single threaded, so you need to return control to the main event handler for the asynchronous callback to be called. If you run a loop, the event that the database query is completed will just wait in the queue and never be handled.
What you can do is to return a promise instead of the result itself. That's an object that keeps track of whether the callback has been called or not, has a property where the callback can put the result, and has a method for getting the result when you need it (which uses a callback, because once you use an asynchrous method it can't be handled completely syncronously).
If you want an actual return value from an asynchronous function, you have no other choice than using either generators or Promises.
You will always have to wrap your functions, or return Promises directly.
One of the best promise libraries out there is bluebird, which also has an explanation for how and why to use it (https://github.com/petkaantonov/bluebird#what-are-promises-and-why-should-i-use-them). If you need to interface with node style callbacks or need to expose an API that relies on node style callbacks instead of promises, it also comes with some convenience methods for automating that conversion.

Categories

Resources