Let's say there is a function like this in a third-party javascript (not NodeJS) module:
Api.IoAsync(parameter, function(err, message) {
...
})
And I want to convert it into a synchronous version like this:
Api.IoSync(parameter)
It will be blocking until complete, and its return value is message if succeed, else err.
Is there an universal and easy way to do this?
You cannot make an asynchronous function behave synchronously in Javascript. This has been asked many times. It cannot be done in Javascript.
If the underlying function is asynchronous, then you will have to code an asynchronous response callback and use the results of the async function that way. There is no work-around.
Learn how to code with async callbacks and move forward. Promises can simplify the use of asynchronous functions by allowing you to sequence and chain async operations more easily, but they still use callbacks to process results.
Related
I'm actually diving into the asyc/await part for the first time so I am having a hard time understanding it.
I know that async await is used to make a function run in an async manner but how, because as per the definition, the "await" keyword halts the execution of a function until the promise is resolved, and then executes the leftover code in the function. Isn't this a synchronous behaviour, because things are getting executed in order as they should be?
Feel free to help me out of my confusion or if I am wrong somewhere.
Neither.
The async and await keywords are tools to manage promises.
Promises are a tool to manage asynchronous code.
If you mark a function as async then:
its normal return value is replaced with a promise that resolves to its normal return value.
you may use await inside it
If you use await on the left hand side of a promise, then the containing function will go to sleep until the promise settles. Execution outside the async function will continue while it sleeps (i.e. is is not halted).
This lets you use syntax that looks like it works on synchronous code to work on asynchronous code.
It doesn't make synchronous operations asynchronous or vice versa.
I have some older Node.js code that I'm updating. In the process I'm designing new modules to work with the old code. I'm finding that now, as opposed to when I first wrote this, I rely more on using ES6 promises rather than callbacks. So now I have this mix of some functions returning promises and some taking callbacks - which is tedious. I think eventually it should be refactored to use promises. But before that is done...
What are the situations where promises are preferred and where are callbacks preferred?
Is there any type of situation that a callback can handle better than a promise and vice-versa?
Based on what I've seen so far, I can't really see any reason to use callbacks instead of promises. Is that true?
First off, you pretty much never want to write code that is a mix of callbacks and promises for async operations. If you're moving to promises or introducing some promises, then you probably want to refactor the callbacks in that same section of code into promises. For the appropriate types of operations, there are so many advantages of promises over plain callbacks that it is well worth the effort to convert when already working in an area of code.
Promises are great for:
Monitoring synchronous operations
That need to notify only once (usually completion or error)
Coordinating or managing multiple asynchronous operations such as sequencing or branching async operations or managing multiple operations in flight at the same time
Propagating errors from nested or deeply nested async operations
Getting code ready for the use of async/await (or using it now with a transpiler)
Operations that fit the Promise model where there are only three states: pending, fulfilled and rejected and where the state transitions from pending => fulfilled or from pending => rejected can then not change (a single one-way transition).
Dynamically linking or chaining asynchronous operations (such as do these two async operations, examine the result, then decide which other async operations to do based on the intermediate result)
Managing a mix of asynchronous and synchronous operations
Automatically catching and propagating upwards any exceptions that occur in async completion callbacks (in plain callbacks these exceptions are sometimes silently hidden).
Plain callbacks are good for things that promises cannot do:
Synchronous notifications (such as the callback for Array.prototype.map())
Notifications that may occur more than once (and thus need to call the callback more than once). Promises are one-shot devices and cannot be used for repeat notifications.
Situations that cannot be mapped into the pending, fulfilled, rejected one-way state model.
And, I'd also add EventEmitter to the mix.
EventEmitters are great for:
Publish/subscribe type notifications
An interface with an event model, particular when events can occur more than once (like streams)
Loose couplings when 3rd party code wants to participate or monitor something without any more of an API than an eventEmitter. No API to design. Just make an eventEmitter public and define some events and the data that goes with them.
Notes about converting plain callback code to Promises
If your callbacks fit the node calling convention with the callback passed as the last argument and called like this callback(err, result), then you somewhat automatically wrap the parent function in a promise with util.promisify() in node.js or if using the Bluebird promise library, with Promise.promisify().
With Bluebird, you can even promisify an entire module (that uses async callbacks in the node.js calling convention) at once such as:
const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));
fs.writeFileAsync("file.txt", data).then(() => {
// done here
}).catch(err => {
// error here
});
In node.js version 8+
There is now util.promisify() which will convert an async function that uses the node.js async calling convention to a function that returns a promise.
Example from the doc:
const util = require('util');
const fs = require('fs');
const stat = util.promisify(fs.stat);
// usage of promisified function
stat('.').then((stats) => {
// Do something with `stats`
}).catch((error) => {
// Handle the error.
});
They both exist to solve the same problem, handle the result of an asnychronous function.
Callbacks tend to be more verbose and coordinating multiple asynchronous requests concurrently can lead to callback hell if you're not actively modularizing your functions. Error handling and tracing tends to be less straightforward and even confusing since there could be many Error objects that all go back to a single error further down the call stack. Errors, also need to be passed back to the original caller that can also lead to some head scratching when determining where the original Error was thrown if anonymous functions were used in the callback chain. One of the benefits of callbacks is that they are just plain old functions and don't require any additional understanding beyond knowing how an asynchronous operation works.
Promises are more common as they require less code, are more readable since they are written like synchronous functions, have a single error channel, can handle thrown errors and with util.promisify() being added in the latest version of Node.js, can convert Error-First Callbacks to promises. There's also async/await which is making its way into Node.js now as well, and they also interface with Promises.
This is totally opinion based, so it really is about what you're most comfortable with but, Promises and async/await are the evolution of the callback and enhance the asynchronous development experience. This isn't an exhaustive comparison by any means but rather, a high level look at both callbacks and promises.
I don't remember from where I got this stuff but might be helpful in understanding promises better.
Promises are not callbacks. A promise represents the future result of an asynchronous operation. Of course, writing them the way you do, you get little benefit. But if you write them the way they are meant to be used, you can write asynchronous code in a way that resembles synchronous code and is much more easy to follow:
ADVANTAGES
1. Readability over callbacks
2. Easy to catch errors.
3. Simultaneous callbacks
1. Readability over callbacks
Promises provide a more succinct and clear way of representing sequential asynchronous operations in javascript. They are effectively a different syntax for achieving the same effect as callbacks. The advantage is increased readability. Something like this
aAsync()
.then(bAsync)
.then(cAsync)
.done(finish);
is much more readable than the equivalent of passing each of those individual functions as callbacks, like
aAsync(function(){
return bAsync(function(){
return cAsync(function(){
finish()
})
})
});
2. Easy to catch errors.
Certainly, not much less code, but much more readable. But this is not the end. Let's discover the true benefits: What if you wanted to check for any error in any of the steps? It would be hell to do it with callbacks, but with promises, is a piece of cake:
api()
.then(function(result) {
return api2();
})
.then(function(result2){
return api3();
})
.then(function(result3){
// do work
})
.catch(function(error) {
//handle any error that may occur before this point
});
/* Pretty much the same as a try { ... } catch block.
Even better: */
api()
.then(function(result){
return api2(); })
.then(function(result2){
return api3(); })
.then(function(result3){
// do work
})
.catch(function(error) {
//handle any error that may occur before this point
})
.then(function() {
//do something whether there was an error or not
//like hiding an spinner if you were performing an AJAX request.
});
3. Simultaneous callbacks And even better:
What if those 3 calls to api, api2, api3 could run simultaneously (e.g. if they were AJAX calls) but you needed to wait for the three? Without promises, you should have to create some sort of counter. With promises, using the ES6 notation, is another piece of cake and pretty neat:
Promise.all([api(), api2(), api3()])
.then(function(result) {
//do work. result is an array containing the values of the three fulfilled promises.
})
.catch(function(error) {
//handle the error. At least one of the promises rejected.
});
Hope you see Promises in a new light now.
Mainly looking at the FS api, for most functions it seems there are three flavors to choose from:
Synchronous
Asynchronous using callback
Asynchronous using promises
Async is the superior way to use system resources, however, if I'm already inside an async function and am awaiting every call anyway then there shouldn't be any difference between that and just using synchronous calls, right? To me it just seems like a built in await statement.
I don't know how async is implemented in js/node though. Is there any advantage to using async functions if I'm inside an async function to begin with? (excluding scenarios when I'm running async tasks in parallel)
One should decide to use an async function ONLY based on what is going on inside that function, not on who is calling it. The caller does not affect whether a function should be async or not.
Reasons to make a function async:
You have promise-based asynchronous operations inside the function and you wish to use await.
You have promise-based asynchronous operations inside the function and you wish to take advantage of the automatic catching of synchronous exceptions (and conversion to a rejected promise) that might occur before you invoke your asynchronous operations.
And, that's pretty much it for the reasons to use the async keyword in front of a function.
Things that an async function is NOT (or common misconceptions about async functions):
It doesn't magically make blocking code become non-blocking.
It doesn't make the caller run faster.
It doesn't make synchronous code now run in the background asynchronously.
Async is the superior way to use system resources,
Not sure what you mean there. Asynchronous functions allow you to run operations in a non-blocking fashion so that the main thread in Javascript can do other things while the asynchronous operation is running, but that is not something that an async function enables. That's enabled by an asynchronous operation. The two are different.
if I'm already inside an async function and am awaiting every call anyway then there shouldn't be any difference between that and just using synchronous calls, right?
Incorrect. Using await with a function that returns a promise does suspend execution of the current function (returning a promise immediately), but that allows the main Javascript thread to do other things, serve other requests, etc... Using synchronous code would be blocking and would not allow the main thread to do other things, thus ruining the scalability of a server.
To me it just seems like a built in await statement.
Blocking, synchronous code affects everything else that could be running during your operation. It's not the same as using await.
async/await is not equivalent to synchronous execution; it's syntactic sugar to make working with promises easier (indeed, the goal of these keywords is to make promises closer to writing synchronous code from a programming standpoint and therefore more intuitive to use).
async places a task on the event loop which will execute after all synchronous execution pending on the stack finishes. The advantages of this are clear: the process can do work while waiting for resources to be available (opening a file involves a system call, for example, so it makes sense to make this a non-blocking operation).
If you're already inside an asynchronous function, the advantages and drawbacks of asynchronous operations are just the same as they would be anywhere else. In fact, await can only be used in an async function.
Iam a node js beginner. I want to do some Job in Node js in a sequential order.
Fetch from DB -> Do some operation -> export as excel -> Mail
As Node js async,Do I need to code like below?
function fetchDB();
function operation(results,callback);
function excel(result,callback());
function mail(result);
fetchDB(operation(results,excel(result,mail(result))));
is the above way is right? or any other good ways to achieve this?
I suggest you read into promises. They allow you to run code immediately after asynchronous code returns. Also see promisejs.org as noted in the comments by #AnnaFohlmeister.
Promises are a more advanced (and cleaner) implementation of callbacks and can allow for more complex chaining of actions after asynchronous code finishes. Using callbacks you tend to run into what is called "callback hell" where you will have a ton of different actions nested into many callbacks and is not easy to write in a modular way (like changing out which operations do what after the end of which call).
As for your code it's correct using callbacks, though when defining excel(result, callback()) remove () on the callback because that will most likely confuse node when it's initializing the functions. Also I'm assuming that your excel function makes another asynchronous call in it.
I'm implementing an API which has a function:
get(url)
Which returns a Response Object, i.e. no callback. The Http Modules I have found implements node-style async functions with callbacks. I have tried to wait for the async function to return in several ways, using Fibers etc. Fibers solves the issue within the Fiber, but can't be used in my case as I need to return the value outside any Fiber.
It might be possible to wrap the Entire Execution (including the code using the API) but I really don't want this. Is there any module that does what I want?
If I understand the question, that you're trying to mix asynchronous code with synchronous code what you're trying to accomplish is not really possible without promises. As soon as you mix asynchronous code with synchronous code, you make the entire code asynchronous, or you risk the synchronous code returning a value before the result from the synchronous code is returned.
You could always try a timeout on the function that holds it returning until a given time period has expired, which hopes that the asynchronous code executes and has a return value before the synchronous code returns. However, this is extremely inefficient, and does not eliminate the problem as you could still end up returning before the asynchronous portion has finished.
I'd also agree with the comment from robertklep that node.js really does not fit your use case, and you might be better looking at another tool for the job.