Understanding Asynchronous Code in Layman's terms - javascript

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.

Related

Understanding callback function purpose

I realise this is more of a general question, but I've read through similar answers on here but I can't find more of an overview. I'm new to callbacks and I'm trying to understand when they should be used.
The MDN web docs has this example;
function greeting(name) {
alert('Hello ' + name);
}
function processUserInput(callback) {
var name = prompt('Please enter your name.');
callback(name);
}
processUserInput(greeting);
However I'm struggling to see how this is more beneficial than the following, where I'm not passing the greeting function as a parameter?
function greeting(name) {
alert('Hello ' + name);
}
function processUserInput() {
var name = prompt('Please enter your name.');
greeting(name);
}
processUserInput();
As Javascript is async, sometimes it is difficult to handle response from non-blocking functions, for ex. if you are making an ajax call then it'll be executed asynchronously and results will be returned sometime later, by that time the main execution flow will pass the ajax code and starts executing following statements, in that case, its very difficult to catch the response to process further.
To handle those cases, callbacks comes into picture where you pass a function as the parameter to the ajax function and once the response is returned then call the callback by passing response data as a parameter to process further.
more info here http://callbackhell.com/
In simple terms you can say a callback is a way of asking a question (or requesting a task) in advance, i.e. when you're done with this do this (usually with the result). The whole point is to set aside functions that are to be done later, usually because you don't have the required inputs to do them now.
The 2 main differences between your implementation and the MDN one is that yours is harder to maintain and harder to reason about hence test.
1. Maintanance / Reusability
Imagine you're a few thousand lines of code into a code base then you're required to change what processUserInput() does. Its much easier to change or write a new callback function instead of changing the function processUserInput(). This would be evident if processUserInput was a bit more complicated. This also means the MDN one is much more useful in various scenarios unlike your implementation. You can reuse it in different situations like saying good bye, capitalizing names etc simply by writing different callbacks to plug into processUserInput().
2. Testing / Easier to reason about
The MDN implementation is much more easier to understand. Its easier to assume that the function processUserInput(greeting) will probably return a greeting than it is to assume what processUserInput() does. This makes it easier to test because you can always be sure the MDN implementation will always return the same output given an input.
Callbacks can be extremely useful depending on the circumstances; for example, when working with JavaScript for Google Chrome browser extension development, a callback can be used for intercepring web requests once it has been setup.
The purpose of a callback in general is to have the callback routine executed upon a trigger - the trigger being an event of some kind. Usually, functionality follows an interface of chained APIs. By implementing callback support, you can redirect execution flow during a stage of an operation. Callbacks are especially useful to third-party developers when dealing with someone elses library depending on what they are trying to do. Think of them like a notification system.
Functions in general taking in parameters is useful for flexibility and maintenance. If you use different functions for different things, the functions can be simply re-used over and over again to provide different functionality - whilst still preventing bloating the source code with more-or-less the same code over and over again. At the same time, if you use functions to your own library and a bug shows up, you can simply patch it for the one function and then it will be solved.
In your example, your passing a callback routine to the function you're calling - the function you're calling will call the callback function and pass the correct parameters. This is flexible because it allows you to have a callback routine called for printing the contents of the variable, and another for calculating the length of the string passed in, or another for logging it somewhere, etc. It allows you to re-use the function you setup, and have a different function called with the correct parameters without re-making the original function.
This example is not appropriate for understanding callbacks
In simple Language callbacks functions are used when we have to do some stuff after or in response of some other event or function or expression.
i.e when the parent function completes its execution then callback gets executed.
simple Example
function hungerStatus(status,cb){
return cb(status)
}
function whatToDo(status){
return status ? "order Pizza" : "lets play"
}
hungerStatus(false,whatToDo)
Another example
// global variable​
​var allUserData = [];
​
​// generic logStuff function that prints to console​
​function logStuff (userData) {
if ( typeof userData === "string")
{
console.log(userData);
}
else if ( typeof userData === "object")
{
for (var item in userData) {
console.log(item + ": " + userData[item]);
}
​
}
​
}
​
​// A function that takes two parameters, the last one a callback function​
​function getInput (options, callback) {
allUserData.push (options);
callback (options);
​
}
​
​// When we call the getInput function, we pass logStuff as a parameter.​
​// So logStuff will be the function that will called back (or executed) inside the getInput function​
getInput ({name:"Rich", speciality:"JavaScript"}, logStuff);
refer callback exaplanation

What are JS Callbacks/Hooks (Meteor: Aldeed Autoform)?

I've been reading about some documentation on Callbacks and Hooks for a meteor application I'm making, which uses the Aldeed Autoform package. I was told hooks would be helpful to me in something that I wanted to do, but I cant actually figure out what Callbacks and Hooks are. An explanation or even a link to a site that explains it would be great, thanks!
A callback is a function that is passed as a parameter to another function:
// Function that accepts a callback
function greet(name, callback) {
var greeting = 'Hello ' + name + '!';
callback(greeting);
};
// Call greet function with name, and anonymous function
greet('Dave', function(greeting) {
alert(greeting); // 'Hello Dave!'
});
It's particularly useful when you want to do something asynchronous, where you don't know how long the process will take, or when it will be completed e.g an AJAX request. You can wrap up the logic you want to be completed after the request has come back in a function, e.g updating the DOM, and it will be executed whenever it needs to be.

Callback() Node Js

I'm very confused about this program. I bought a book called "Node JS, MongoDB, and AngularJS Web Development" by Brad Dayley. I found a program to demonstrate something called closure, and it shows this program as an example. This is only the first part of the program.
function logCar(logMsg, callback){
process.nextTick(function(){
callback(logMsg);
});
}
var cars = ["Ferrari", "Porsche", "Bugatti"];
for(var idx in cars){
var message = "Saw a " + cars[idx];
logCar(message, function(){
console.log("Normal Callback: " + message);
})
}
I've been trying to figure out how this program functions for an entire hour, but I can't figure out what the function of callback(logMsg).
I know this is probably a very basic question, but I just can't wrap my head around it.
callback is any function that you pass to logCar(). When logCar completes doing whatever it is supposed to do, then it will call the callback function. Inside your for loop, you call logCar() like this..
logCar(message, function(){
console.log("Normal Callback: " + message);
})
Here, function() {..} is the callback function and it will be called once logCar is done executing. In this case, the callback function you've provided will console.log the message you've passed as the first parameter. You could have passed another function that would perform something different as a callback too.
I find these easier to wrap my head around by following the execution path more closely, especially the path that logMsg takes. A good debugger is great for this.
Nothing really happens until that for loop, where a variable named message is defined. At the start it will be "Saw a Ferrari".
There's also an anonymous function right next to "message" that's unfortunately difficult to separate out and define. Because it looks outside of its scope for a variable named "message" that's trapped inside that for loop, we couldn't do on line 6:
var someFunction = function(){
console.log("Normal Callback: " + message);
}
...because what's "message"? Nothing outside of that for-loop has access to "message" directly (except as closure, but don't worry about that yet). Note that this function won't execute yet. It's just been created at this point.
So next executes LogCar("Saw a Ferrari", someFunction...). Where's LogCar? Oh, the top. Let's jump there, but for simplicity let's skip process.nextTick. Essentially someFunction("Saw a Ferrari") happens here. Where's SomeFunction? Oh, that's that anonymous function that hasn't executed yet. Now its time to execute has arrived. So the process jumps back there to see what's inside it and execute it, which is console.log("Saw a Ferrari");
That's done, and the process repeats for "Saw a Porsche" .

Set object values from asynchronous function

How do I set an object's properties from an asynchronous function without losing the values? Someone on another SO thread said that anything that has to do with this function should be kept inside the function. However,I want to assign values from it, and assign it to an object. I'm a little new to OOP Js, so this was confusing to me.
I have this function that gets the user's location. This HTML5 function requires a callback to pass a position object into.
function getInfo()
{
navigator.geolocation.getCurrentPosition(getPos);
}
This is the function that is referenced in getCurrentPosition().
function getPos(position)
{
PositionObj.lat = position.coords.latitude;
PositionObj.lon = position.coords.longitude;
}
PositionObj:
var PositionObj =
{
lat:null,
lon:null,
returnLat: function()
{
return this.lat;
},
returnLon: function()
{
return this.lon;
}
};
When I try to access PositionObj's properties, I get null, and not the new value that was assigned by the callback. How do I go about doing this? I've tried things like making the callback an object itself, and passing the values to another function that assigns values to the object. Any help would be appreciated!
The most important question is: when are you trying to access PositionObj's properties? Since the whole thing is asynchronous, you won't see any value in lat or lon until the location is retrieved and getPos assigns it. Thus, something synchronous like:
getInfo();
console.log(PositionObj.lat);
is definitely not going to work. getInfo returns immediately and doesn't wait for the location to come in. That's a good thing: the whole idea about asynchronism is that you don't wait (block) until you get your results. Instead, you give a callback to the function and that function makes sure to call it when the results are retrieved later on. In Hollywood style: "don't call me, I call you!"
Thus, anything that relies on the actual position retrieved by getInfo needs to be in the callback. This means that you have to think and code differently: you'll need to break up your synchronous function into smaller functions which are chained up as callbacks.
In your case, you'd put that console.log(PositionObj.lat) (or anything else you want to do with the position) inside (what you called) getPos (you probably want to think of a better name for that function though).
Here's a more complete example which demonstrates the concept better. An online shop may have something like this on its checkout page:
var position = getPosition(); // using geolocation
var closestShop = getClosestShop(position); // using AJAX to a server-side script
alert("The closest shop is " + closestShop);
However, all those synchronous calls would block the script's execution and the page would "freeze". The user would probably think that his browser crashed, and that's not a great user experience.
If all these actions were asynchronous, you'd restructure it so it looks like this:
getPosition(function(position) {
getClosestShop(position, function(closestShop) {
alert("The closest shop is " + closestShop);
});
});
Here, each function accepts a callback function which it calls when the results are in. They all return immediately, allowing the script to continue execution and keep the page responsive. Of course, nothing stops you from starting another asynchronous action from within this callback, effectively chaining them up.
In fact, this last pattern is so popular that a new mechanism was created to make it more manageable: promises. The inner workings are still the same (functions accepting a callback instead of blocking synchronously) but it looks more pleasant. When you make getPosition and getClosestShop return a promise, you could write:
getPosition().then(getClosestShop).then(function(closestShop) {
alert("The closest shop is " + closestShop);
});

access a json string from outside the call back function that read it

var plane;
$.getJSON(sTailFileName, function(plane) {
$('#upTailNum').html(plane.tailNum + ' ' + plane.airplaneType);
document.title="Load " + plane.tailNum;
.... goes on for 300+ statements ....
});
and it works fine. However, what I want to do is something like:
var plane;
$.getJSON(sTailFileName, function(plane) {});
$('#upTailNum').html(plane.tailNum + ' ' + plane.airplaneType);
document.title="Load " + plane.tailNum;
but that gives me a "plane undefined" message. I need to get at plane from outside the scope of the getJSON -- or at least want to. I've tried many things including $.proxy and through closures (which I don't yet really understand), but with no success thus far.
This is my first effort in Javascript/jQuery. I'm attempting to replace an old DOS program I originally wrote back in 1988. See http://terryliittschwager.com/WB/wbjs.html for details.
Any help will be greatly appreciated!
Terry Liittschwager
Your callback function to getJSON gets the plane value but doesn't do anything with it; so, when you do plane.tailNum, plane is still undefined because it was never assigned a value. Also, the getJSON call is asynchronous so you can't just do this:
$.getJSON(sTailFileName, function(x) { plane = x; });
because the plane = x will not have been executed (unless you get very lucky with the timing) when you try to access plane.tailNum.
You can replace the getJSON call with a synchronous $.ajax call and assign the JSON blob to plane in the success callback or keep doing things the first way. You can always put your "goes on for 300+ statements" in a separate named function, say, three_hundred_lines and refer to that by name:
function three_hundred_lines(plane) { /* ... */ }
$.getJSON(sTailFileName, three_hundred_lines);
if you don't want to inline a big pile of code.
The thing with AJAX calls is that they're asynchronous. You can access the returned value within the callback function because the callback function happens once the data is returned.
$.getJSON(); just fires off the request and returns immediately. Any code that immediately follows it will be executed before the json data returns.
The problem is that $.getJSON is an asyncronous method ie, the line $.getJSON(sTailFileName...) sends off the request but doesn't wait around for the result to be returned before continuing to the next line. The function that is supplied to $.getJSON is called once a response is recieved, which is almost certainly after the rest of the program has executed.
You shouldn't attempt to work around this. The callback function is the correct place to handle the response.
You are used to programming synchronously. You need to wrap any logic that uses the plane object in a function, and invoke that function from your getJSON callback. Something like this:
$.getJSON(sTailFileName, function(plane) {
// pass "plane" along to some other function that does the work
doStuff(plane);
});
The reason you are sending a function as an argument to getJSON is because you don't know when the response will be received.
Although I was born in 1988 when you were writing DOS programs, so if you want me to get off your lawn, I'm fine with that ;-)
-tjw

Categories