How to Avoid Long Nesting of Asynchronous Functions in Node.Js

How to avoid long nesting of asynchronous functions in Node.js

Interesting observation. Note that in JavaScript you can normally replace inline anonymous callback functions with named function variables.

The following:

http.createServer(function (req, res) {
// inline callback function ...

getSomeData(client, function (someData) {
// another inline callback function ...

getMoreData(client, function(moreData) {
// one more inline callback function ...
});
});

// etc ...
});

Could be rewritten to look something like this:

var moreDataParser = function (moreData) {
// date parsing logic
};

var someDataParser = function (someData) {
// some data parsing logic

getMoreData(client, moreDataParser);
};

var createServerCallback = function (req, res) {
// create server logic

getSomeData(client, someDataParser);

// etc ...
};

http.createServer(createServerCallback);

However unless you plan to reuse to callback logic in other places, it is often much easier to read inline anonymous functions, as in your example. It will also spare you from having to find a name for all the callbacks.

In addition note that as @pst noted in a comment below, if you are accessing closure variables within the inner functions, the above would not be a straightforward translation. In such cases, using inline anonymous functions is even more preferable.

Nodejs: How to avoid nested .then() when using async/await

for this line : requester.makeRequest ... .then(function(city){

replace .then(function(city){ with var city = await requester.makeRequest , city will have the fulfilled value of the promise, do this for the rest of thens :

( keep in mind that await is only used inside an async function, you can use an iife )

(async () => {

var city = await requester.makeRequest(`${geocode_url}?locate=${req.query.q}&json=1${geocode_token}`);

var final_result = []
var lat = city.latt;
var long = city.longt;
// request to get list of cities closer to that location,
//takes latitude and longitude as parameters
var closer_cities = await requester.makeRequest(`${metaweather_url}?lattlong=${lat},${long}`);

var cities_len = closer_cities.length;

for (i = 0; i < closer_cities.length; i++) {
woeid = closer_cities[i].woeid
//request to get weather using woeid parameter
var weather = await requester.makeRequest(woeid_url + woeid);

var lattlong = weather.latt_long;
var onwater = await requester.makeRequest(`${onwater_url}${lattlong}?access_token=${water_access_token}`);

var temp = Object.assign(weather, onwater)
final_result.push(temp)
if (final_result.length == cities_len) {
res.status(200).json({
error: false,
data: {
message: final_result
}
})
}
}

})();

How do I avoid deeply nested code in node.js?

I wrote a library based on node-seq, which looks like this:

app.get('/test', function (req, res) {
Seq()
.seq(function () {
http.get('some/place', this.next)
})
.seq(function (req1, res1) {
if (res1.statusCode == 200) {
res1.on('data', this.next)
}
})
.seq(function (data) {
http.get('other/place?q=' + data, this.next)
})
.seq(function (req2, res2) {
if (res2.statusCode == 200) {
res2.on('data', this.next)
}
})
.seq(function (data) {
db.query(data).on('data', this.next)
})
.seq(function (rows) {
res.writeHead(200)
res.end(JSON.stringify(rows))
})
})

The code is here.

Also, there's a lengthy discussion on the nodejs mailing list about this issue.

Step is another library for doing this stuff.

Nesting async class methods / functions in JavaScript

Not sure if "nesting" is the right term here, it sounds like you are trying to call the one method from the other. The correct way to do that is

class ExternalDb {

async getDbData(){
const data = await getExternalDbInfo(this.extdb_user, this.extdb_password, this.extdb_privilege, this.extdb_ip, this.extdb_port, this.extdb_sid);
return data;
// ^^^^
}
async getTablespace(){
const data = await this.getDbData();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
console.log(data);
return data.tablespace_data;
}
}

You would then not chain anything, but simply call

const x = await newDb.getTablespace();
console.log(x);

Writing custom, true Asynchronous functions in Javascript/Node

Just a side note, true asynchronous doesn't really mean anything. But we can assume you mean parallelism?.

Now depending on what your doing, you might find there is little to no benefit in using threads in node. Take for example: nodes file system, as long as you don't use the sync versions, it's going to automatically run multiple requests in parallel, because node is just going to pass these requests to worker threads.

It's the reason when people say Node is single threaded, it's actually incorrect, it's just the JS engine that is. You can even prove this by looking at the number of threads a nodeJs process takes using your process monitor of choice.

So then you might ask, so why do we have worker threads in node?. Well the V8 JS engine that node uses is pretty fast these days, so lets say you wanted to calculate PI to a million digits using JS, you could do this in the main thread without blocking. But it would be a shame not to use those extra CPU cores that modern PC's have and keep the main thread doing other things while PI is been calculated inside another thread.

So what about File IO in node, would this benefit been in a worker thread?.. Well this depends on what you do with the result of the file-io, if you was just reading and then writing blocks of data, then no there would be no benefit, but if say you was reading a file and then doing some heavy calculations on these files with Javascript (eg. some custom image compression etc), then again a worker thread would help.

So in a nutshell, worker threads are great when you need to use Javascript for some heavy calculations, using them for just simple IO may in fact slow things down, due to IPC overheads.

You don't mention in your question what your trying to run in parallel, so it's hard to say if doing so would be of benefit.

Correct error handling of nested async functions with promise

No you cannot catch same error twice. The method of relaying error will be buggy. instead what I would do is to just forward the outputs and handle them in the outer function.

const innerFunction = async () => asyncFunction(false); // <-- Just return the outputs
const outerFunction = async () => {
try {
const result = await innerFunction(); // <-- Error is forwarded and thus handled
} catch (error) {
console.log("Caught error inside outerFunction");
}
};

Am I over-nesting in JavaScript Async/Await

This might be a good question for code review

I have two ideas for reducing nesting. One is using a catch function instead of try catch blocks, i.e.

const err = e => console.error(e);

const func1 = async () => {
// do something
const resultForFunc2 = // the end result of doing something that is going to be used in func2
return {statusCode: 200, body: resultForFunc2, error: null}
}

const result1 = await func1.catch(err);

Another idea is to exit on a fail instead of nest the continuing code inside a block. i.e.

const all = async () => {
const response1 = await func1().catch(err);
if (response.statusCode !== 200) return { statusCode: 400, error: response.error, body: null };
const response2 = await func2().catch(err);
if (response2.statusCode !== 200) return { statusCode: 400, error: response2.error, body: null };
//and so on
}


Related Topics



Leave a reply



Submit