Callback function confusion - javascript

function print(){
console.log("hello");
}
Fruit.find(function(err,fruits){
mongoose.connection.close();
if(err){
console.log(err);
}else{
// console.log(fruits);
fruits.forEach(function(fruit){
console.log(fruit.name);
})
}
})
Just a background :
the fruits model has a array of objects (fruits) and each fruit has a name with the code above I am displaying only its name
I am confused abut how we are closing mongoose connection even before logging the text also read at a article that its a callback function so gets executed after completion after execution of all steps so another question is how I know wether its a callback or a normal function also if I had another function print to make it callback (for the loop) how do I make it i.e print Hello after logging all the name of fruits but writing before log statement of fruits name

I am confused abut how we are closing mongoose connection even before logging the text
The callback function gets called when the data has been read from the mongoose connection.
The data is passed to the fruits argument.
You don't need the connection to be open after the data is already in a local variable.
how I know wether its a callback or a normal function
Callback functions are normal functions. It is just how they are used. See MDN:
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.

Related

Javascript returns result before all parameters evaluated?

I found the following example in ngResource documentation:
var cards = CreditCard.query(function() {
// GET: /user/123/card
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
var card = cards[0];
// each item is an instance of CreditCard
expect(card instanceof CreditCard).toEqual(true);
card.name = "J. Smith";
// non GET methods are mapped onto the instances
card.$save();
// POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
// server returns: {id:456, number:'1234', name: 'J. Smith'};
// our custom method is mapped as well.
card.$charge({amount:9.99});
// POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
});
As I can understand, the second parameter of function query() is a function, which evaluated on success result of resource query. But simultaneously, this function takes the variable cards which is assigned from result of function query().
I can't understand, if this is normal to Javascript, since every async operation executes single thread?
Or special efforts were taken by creators of AngularJS in order to have function paramater executed after it's result returned?
How would I write my own function
function myfunction(argument, runbefore, runafter) {
runbefore();
POSTPONE runafter();
return Math.sin(argument);
}
which would execute 2nd parameter before itself and 3rd parameter -- after itself?
If I understand right, you are asking how it is possible for the callback function to be called after the return statement. One way that this is possible is through builtin functions that call another function at a later time. Take this code for example:
function doItLater(arg1, callbackFn) {
setTimeout(1000, callbackFn);
return arg1;
}
This will return the same argument that it was passed, and the callback function will be called later (about 1 second after the function has already returned). There are other ways a callback function can be delayed. For example, with an XMLHttpRequest, a callback function can be called after an HTTP response has been received. You can also connect to user events, so that a function will be called when the user does something specific.
If you want a little clarification on how things like setTimeout work in a single-threaded environment, I would suggest reading this article by John Resig.

Executing a Parent callback function when child function completes - Javascript

I have a function that takes a callback as a parameter, this function has a child function inside of it that I need to actually execute the passed callback that was passed to the parent when it's (the child function) done.
Example:
function Update(callback){
var db = Ti.Database.open('xxxxx'); //Open local database
var data = Ti.Network.createHTTPClient(); //Open a URL to obtain data to put into db.
data.onload = function(){
//loop through JSON file obtained from HTTPClient and place data into the DB.
callback(); //I need THIS to trigger the parents callback to tell the next function that Update() is done.
}
data.open("GET","URL");
data.send();
}
I'm pretty unexperienced when it comes to callbacks, so maybe I'm over thinking this one. Any help would be appreciated! Thanks all!
EDIT: Fixed - This code above works as expected. Somehow, because this Update function was being called while the DB was being created (another function creates the DB, then that callback function calls this Update function), it was still updating the DB, but wasn't calling the callback inside onload. I called the callback to trigger Update later, and it now works as expected. There were never any errors in the Appcelerator Console, so I'm not exactly sure how or why the DB was updated without the callback being called, but it was.

how does the callback in fs.readfile get called when using fs.readfile.bind(context,pathArgument)

How does the callback in fs.readfile get called when using fs.readfile.bind(context,pathArgument) like so. //understandable because my task function knows the name of the callback parameter
async.series([function(callback){
//operation done callback()},...],finalCallback(err,result));
BUT
//not understandable
async.series([fs.someOperation.bind(null,firstArgument),...],finalCallback(err,esult))
I believe I understand partial application;however, it would look something like this. function(callback){ fs.someOperation(firstArgument, ????)}(asyncCallbackFunc) and then I have no idea how the second argument is called...
Thx, in advance for helping me clear this up.
All bind does is set the context of the callback. It is still a regular callback like any other. Except, it is explicitly told what this will be. Looks like in your case, it is set to null.
The bind function on function object allows you to set the context i.e the value of this inside the function body as well as allow you to create a partial function in case you pass some arguments while calling bind.
For example:
function add(a,b) {
console.log(this);
return a+b;
}
var newAdd = add.bind("hello world", 10);
The newAdd will be one argument function which gets added to 10 and the result is returned. Also when newAdd is called the "hello world" will be logged in console.
Now when your code says fs.readFile.bind(null, path) it means that the return function will be of one argument which is the callback for readfile i.e the return function will be of form function(callback) { ... } which is exactly what is required to be passed to async.series
The main idea in the code you posted is to create a partial function that accepts only callback so that it can be passed to async.series the null argument doesn't play any role but you need to pass a context argument to call bind function, hence a null is passed as context arg.

Is there any way to break Javascript function within an anonymous function?

I just want to check if the data I'm about to insert allready exists on my Firebase, and if so I just want to break the add function:
FBDB.addCampain=function (campain){
CampiansRef.once('value',function(snapshot){
snapshot.forEach(function(childSnapshot){
if(campain.Name==childSnapshot.val().Name){
console.log("campain allredy exists on the DB");
return false; //I want to break the addCampain function from here!
}
});
});
var newCampainRef = CampiansRef.push();
campain.id = newCampainRef.key();
newCampainRef.set(campain,function(error){
if(error){
console.log("an error occured the campain did not add to the DB, error:" ,+error);
return false;
}
else{
console.log("campain succssesfuly added to the DB");
return true;
}
});
};
What currently happens is that even if the campaign exists on the database it still continues to the actual adding code. There must be a way to "break" the addCampain function within an anonymous function inside it, or even pass the "return false" up to the main scope.
If you add a few console.log statements, you'll be able to see how your code flows:
console.log('1. starting call to Firebase');
CampaignsRef.once('value',function(snapshot){
console.log('3. for value from Firebase');
snapshot.forEach(function(childSnapshot){
console.log('4. inside childSnapshot');
if (campaign.Name==childSnapshot.val().Name){
console.log("campaign already exists on the DB");
return false;
}
console.log('5. done with snapshot.forEach');
});
});
console.log('2. we started the call to Firebase');
The output will look like:
1. starting call to Firebase
2. we started the call to Firebase
3. for value from Firebase
4. inside childSnapshot
4. inside childSnapshot
4. inside childSnapshot
5. done with snapshot.forEach
This is probably not entirely what you expected. 2. is at the end of the code block, but it fires right after 1. which is at the start. This is because on starts an asynchronous load of the data from Firebase. And since this takes time, the browser continues with the code after the block. Once the data is downloaded from Firebase's servers, it will invoke the callback and you can do what you want. But by then, the original context has finished.
There is no way in JavaScript to wait for an asynchronous function to finish. While you might appreciate if such a way existed, your users would be frustrated by the fact that their browser locks up while your call to Firebase is out.
Instead you have two options:
pass a callback into the function
return a promise
I'm going to use option 1 below, because it is what the Firebase JavaScript SDK already does.
FBDB.addCampaign=function (campaign, callback){
CampaignsRef.once('value',function(snapshot){
var isExisting = snapshot.forEach(function(childSnapshot){
if(campaign.Name==childSnapshot.val().Name){
return true; // this cancels the enumeration and returns true to indicate the campaign already exists
}
});
callback(isExisting);
});
};
You'd invoke this like:
FB.addCampaign(campaign, function(isExisting) {
console.log(isExisting ? 'The campaign already existed' : 'The campaign was added');
};
Note that loading all campaigns from the server to check if a specific campaign name already exists is pretty wasteful. If you want campaign names to be unique, you might as well store the campaigns by name.
CampaignsRef.child(campaign.Name).set(campaign);
From the Firebase documentation, snapshot.forEach returns true if your callback function "cancels the enumeration by returning true". So just change your return false to return true!
Set a "global" (to your addCampaign function) flag in the forEach loop just before breaking out of it, then check this flag when you get back into your main function and return if it is set.

asynchronous JavaScript static function variable

I have a problem with a "static" function in javascrip (nodejs server).
User.create = function(data, _callback){
var node = db.createNode(data);
var _user = new User(node);
_user.save(function(err){
if(err) return callback(err, null);
_user.index(function(err){
if(err) return callback(err, null);
callback(null, _user);
})
})
};
If I call this function twice the _user variable in the internal callback function takes the new value, it seems it overrides the function var instead of allocate a new one.
I need calling this function to allocate a new variable, so it waits save and index functions to complete without changing _user variable.
JavaScript variables are indeed function scoped, so there wouldn't be any explanation for var _user not defining a new variable on subsequent runs.
Looking at the code, I would be more suspicious of what's happening in your User constructor - perhaps it contains some scoping or other logical issues resulting in identical users being created on subsequent calls. Similar "suspects" would be the data parameter getting passed in, as well as db.createNode(). Only suggesting these areas, because it's more likely that there's a programmatic issue at play, rather than JavaScript not following the rules :)
Also, I noticed that your User.create function accepts a parameter called _callback, but later on is invoking callback. I don't know if that's a typo in your example, or if you're accidentally invoking a callback from a higher scope not shown in the example, but that could produce weird behavior.

Categories