I understand the basic thing about asynchronous-ness: things don't execute sequentially. And I understand there is something very powerful about that... allegedly. But for the life of me I can't wrap my head around the code. Let's take a look at async Node.JS code that I HAVE WRITTEN...but don't truly get.
function newuser(response, postData) {
console.log("Request handler 'newuser' was called.");
var body = '<html>' +
'<head>' +
'<meta http-equiv="Content-Type" content="text/html; ' +
'charset=UTF-8" />' +
'</head>' +
'<body>' +
'<form action=" /thanks" method="post">' +
'<h1> First Name </h1>' +
'<textarea name="text" rows="1" cols="20"></textarea>' +
'<h1> Last Name </h1>' +
'<textarea name="text" rows="1" cols="20"></textarea>' +
'<h1> Email </h1>' +
'<textarea name="text" rows="1" cols="20"></textarea>' +
'<input type="submit" value="Submit text" />' +
'</body>' +
'</html>';
response.writeHead(200, { "Content-Type": "text/html" });
response.write(body);
response.end();
}
Where did response come from again? postData? Why can't I define a variable in this "callback" and then use it outside of the callback? Is there a way to have a few things be sequential then the rest of the program async?
I'm not sure where this function is being used, but the point of callbacks is that you pass them into some function that runs asynchronously; it stores your callback away, and when that function is done with whatever it needs to do, it will call your callback with the necessary parameters. An example from front-to-back is probably best.
Imagine we have a framework, and in it there is an operation that runs for a long time, fetching some data from the database.
function getStuffFromDatabase() {
// this takes a long time
};
Since we don't want it to run synchronously, we'll allow the user to pass in a callback.
function getStuffFromDatabase(callback) {
// this takes a long time
};
We'll simulate taking a long time with a call to setTimeout
; we'll also pretend we got some data from the database, but we'll just hardcode a string value.
function getStuffFromDatabase(callback) {
setTimeout(function() {
var results = "database data";
}, 5000);
};
Finally, once we have the data, we'll call the callback given to us by the user of the framework's function.
function getStuffFromDatabase(callback) {
setTimeout(function() {
var results = "database data";
callback(results);
}, 5000);
};
As a user of the framework, you'd do something like this to use the function:
getStuffFromDatabase(function(data) {
console.log("The database data is " + data);
});
So, as you can see data
(same as response
and postData
in your example) came from the function that you pass your callback into; it gives that data to you when it knows what that data should be.
The reason you can't set a value in your callback and use it outside the callback is because the callback itself doesn't happen until later in time.
// executed immediately executed sometime in the future
// | | by getStuffFromDatabase
// v v
getStuffFromDatabase(function(data) {
var results = data; // <- this isn't available until sometime in the future!
});
console.log(results); // <- executed immediately
When the console.log
runs, the assignment of var results
hasn't happened yet!
You have several unrelated questions here:
1) The power of async is being able to do multiple things at the same time without locking the main thread. In node and js in general, this applies particularly to ajax file requests. This means that I can fire off several async calls to retreive files, and not lock the main thread while it renders the content. My preferred framework is jQuery, which has convenient $.Deferred that wraps and standardizes async calls for jQuery usage.
2) response and postData come from the parent method. There's nothing magical here, it's a normal function call, so the values of these are created elsewhere and passed into this invocation. Depending on which node framework you have, the exact signature of your method will change.
3) You can define a global variable in your callback if it's properly scoped. It seem though that you need help learning what scope is. Here are some links
http://www.digital-web.com/articles/scope_in_javascript/
http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/
4) Once you go async, you can never go back, however, by leveraging promise and deferred objects like with jQuery Deferreds you can wait for several asyncs to complete before continuing your execution in yet another async. Deferreds are your friends.
http://api.jquery.com/category/deferred-object/
Looks like you're working through the Node Beginner Book. I encourage you to work through the entire book, it really is an excellent introduction. If you are trying to understand Javascript better, Douglas Crockford's videos on YouTube are a great overview: 1, 2.
The piece of code you've posted doesn't have enough context for me to really help you. response
is a parameter that you're passing to your function, it does not come from postData. If you are working with code the way the Node Beginner Book suggests, you are probably passing response to your newuser function all the way down from the createServer function, which is part of the http module that comes with Node.
You can't define a variable in the callback and then use it in the callback because Javascript is lexically scoped. Here's a Stack Overflow post on the topic of Javascript's scope. The first video by Doug Crockford that I posted also has a great explanation of Javascript's scoping rules.
Javascript isn't necessarily async. It simply provides anonymous functions that are closures, which are a useful tool for easily implementing async logic. Again, the Node Beginner Book shows a good example of writing synchronous code with Node (not what you want), then rewriting it to make it async.