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" .
Related
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
Ok, this is out of "academic interest" (although I'm thinking of using it somewhere). Suppose I have the following:
function f2 ()
{
delete Widget.f1;
Widget.f3 = function ()
{
console.log("This works.");
}
}
let Widget =
{
f1: function ()
{
f2();
}
}
console.log(Widget);
Widget.f1();
console.log(Widget);
Widget.f3();
So basically I call upon a method to remove itself from the object and be replaced with another method. It seems to work fine. So here are my two questions:
Is there a good (technical) reason why I should not do this?
From an "in the bowels of JavaScript" point of view, how does this work? Intuition would say that f1 remains "open" until it has been completed, which would mean that we delete a function that is still "open". Is the f2() call somehow "hoisted" out of it?
Cheers
Is there a good (technical) reason why I should not do this?
The main reason i would not use this is that it is confusing and likely to cause bugs when other developers (including future-BVDev) either don't notice that you're doing it, or don't understand why you're doing it.
From an "in the bowels of JavaScript" point of view, how does this work?
Widget.f1 is a reference to a function, it's not the function itself. So when you delete Widget.f1, that reference is now gone, but the function continues to exist in memory. It also continues to exist on the current execution stack. If there are other references to the function, then it will continue to exist after the call stack has finished. On the other hand if this was the only reference to the function, then some time later, the garbage collector will run and free the memory that the function was taking up.
I'm trying to inline-load a Google Chrome extension using the chrome.webstore.install( link, success, fail) function.
Here's the link from within my page's <head> stanza.
<link rel="chrome-webstore-item"
href="https://chrome.google.com/webstore/detail/oafp--redacted--ffencd" />
Here's the button.
<input type="button" class="btn btn-default" onclick="getExtension();">Go</input>
Here's the Javascript, which appears right before the closing </body> tag.
<script type="text/javascript">
function getExtension() {
function extensionFailed(reason) {
console.log("extension Install Failed:", reason);
}
function extensionInstalled() {
console.log("installed");
};
console.log("calling install");
chrome.webstore.install(undefined, extensionInstalled(), extensionFailed());
console.log("install returned");
};
</script>
Clicking the button that calls getExtension gets me this sequence of events, delivered one after the other immediately.
"calling install" (right before call to chrome.webstore.install())
"installed" (in success callback)
"extension Install failed, undefined" (in failure callback)
"install returned." (after return from call to chrome.webstore.install())
Somewhere in the middle of that, asynchronously, I get the inline installation popup and accept it.
I thought...
the failure callback should only get called on failure.
the failure reason should be something meaningful, not undefined.
the success callback should be deferred until the user accepts the installation.
I must be doing something wrong. ...
Answer:
In this line of code:
chrome.webstore.install(undefined, extensionInstalled(), extensionFailed());
You're actually executing the functions by having the () in extensionInstalled() and extensionFailed(). If you want to pass them in as callbacks, you can actually pass in the functions themselves as you would a var:
chrome.webstore.install(undefined, extensionInstalled, extensionFailed);
Functions as variables:
Note: This does not apply to your code because you define your functions before you call them, which is good practice.
You can also define variables as functions, which IMO only makes things more confusing. Take for example, these 2 function definitions:
var myfunctionVar = function() {
console.log('hello, world');
}
function myfunction() {
console.log('hello, world');
}
You would call these functions in a normal way (i.e. myfunctionVar() and myfunction()).
The key difference between these 2 definitions is that myfunctionVar will only become available once the definition itself is executed whereas myfunction is immediately available in the scope of the parent function that defines it (or once your script file is executed if there is no parent function). This is due to "hoisting", which only makes things more complicated.
In this example, you would not be able to call myfunctionVar() before you assign it. However, this would not be the case for calling myfunction(), and you can call it anywhere in the parent function.
See this answer for a more information.
Functions are a bit more complicated (and powerful!) in Javascript than in other languages, so hopefully this answer clears a few things up for you. You can read about hoisting from W3Schools, here.
I am quite new to the world of async. I am trying to do everything with callbacks at first before using any of the libraries out there. I think I have a closure problem, but don't know what to do about it.
Here is some code:
namespace.on('connection', function(socket){
var newClient = socket.id//just in case the a new user logged on between declaration and use
socket.join('room1')
function newConnection(positionCallback, hashCallback, newUser){
namespace.to(socket.id).emit('hello', {yo:'works'})
for(var i=0; i< cardCounter ;i++){
var keyVal = 'card:'+ cardArray[i]
redis.hgetall(keyVal, function (err, storedMsg) {
namespace.to(socket.id).emit('hello', {yo:'doesnt work'})
hashCallback(storedMsg, newUser)
});
if(i==cardCounter-1){
positionCallback()
}
}
}
function onConnectionComplete(){
namespace.to(socket.id).emit('hello', {yo:'works'})
}
function onHashComplete(hashObject, newUser){
namespace.to(newUser).emit('hello', {yo:'doesnt work'})
}
newConnection(onConnectionComplete, onHashComplete, newClient)
}
I have placed some socketio emits around the place to pinpoint where things go wrong.
Any emits outside of the call to redis work as expected. As soon as I go inside that anonymous function - nada.
That said, I have console.log()'ed everything inside that function. I get the right results from redis, I have the right user, and namespace is defined.
I just can't emit the result.
I would have thought that the anonymous function had access to the scope just outside it - but not the other way around. I don't see what is not making it across...
Also I know that some people don't like the if statement to invoke a callback, but that might be a discussion for another day.
It was a closure problem! Just not what I was expecting.
I also, ahem, don't really understand it.
The callback isn't the problem, getting variables accessible inside the redis response function is. I would have thought that any variables declared in a parent/ancestor function are available to children/decedent functions.
In this instance I needed to create a function inside the loop, and explicitly pass variables for it to be available inside a closure.
Here is the stackoverflow question that pointed me in the right direction:
How can I access the key passed to hgetall when using node_redis?
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