How to avoid long nesting of asynchronous functions in Node.js
I want to make a page that displays some data from a DB, so I have created some functions that get that data from my DB. I'm just a newbie in Node.js, so as far as I understand, if I want to use all of them in a single page (HTTP response) I'd have to nest them all:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
getSomeDate(client, function(someData) {
html += "<p>"+ someData +"</p>";
getSomeOtherDate(client, function(someOtherData) {
html += "<p>"+ someOtherData +"</p>";
getMoreData(client, function(moreData) {
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
});
});
});
If there are many functions like that, then the nesting becomes a problem .
Is there a way to avoid this? I guess it has to do with how you combine multiple asynchronous functions, which seems to be something fundamental.
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.
Kay, simply use one of these modules.
It will turn this:
dbGet('userIdOf:bobvance', function(userId) {
dbSet('user:' + userId + ':email', 'bobvance@potato.egg', function() {
dbSet('user:' + userId + ':firstName', 'Bob', function() {
dbSet('user:' + userId + ':lastName', 'Vance', function() {
okWeAreDone();
});
});
});
});
Into this:
flow.exec(
function() {
dbGet('userIdOf:bobvance', this);
},function(userId) {
dbSet('user:' + userId + ':email', 'bobvance@potato.egg', this.MULTI());
dbSet('user:' + userId + ':firstName', 'Bob', this.MULTI());
dbSet('user:' + userId + ':lastName', 'Vance', this.MULTI());
},function() {
okWeAreDone()
}
);
For the most part, I'd agree with Daniel Vassallo. If you can break up a complicated and deeply nested function into separate named functions, then that is usually a good idea. For the times when it makes sense to do it inside a single function, you can use one of the many node.js async libraries available. People have come up with lots of different ways to tackle this, so take a look at the node.js modules page and see what you think.
I've written a module for this myself, called async.js. Using this, the above example could be updated to:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
async.series({
someData: async.apply(getSomeDate, client),
someOtherData: async.apply(getSomeOtherDate, client),
moreData: async.apply(getMoreData, client)
},
function (err, results) {
var html = "<h1>Demo page</h1>";
html += "<p>" + results.someData + "</p>";
html += "<p>" + results.someOtherData + "</p>";
html += "<p>" + results.moreData + "</p>";
res.write(html);
res.end();
});
});
One nice thing about this approach is that you can quickly change your code to fetch the data in parallel by changing the 'series' function to 'parallel'. What's more, async.js will also work inside the browser, so you can use the same methods as you would in node.js should you encounter any tricky async code.
Hope that's useful!
链接地址: http://www.djcxy.com/p/79300.html上一篇: 并发性和并行性之间的区别是什么?