I am new to javascript and I am trying to understand callbacks. I am not able to understand why 20 is getting printed before 10. My understanding is for a callback function like - func1(parameter,func2()) , func2() is the callback function, which gets executed after func1 executes with the "parameter" passed to func1. Is my understanding correct?
function timePass(length){
console.log("finished after doing timePass for "+length +" seconds")
}
timePass(10,timePass(20));
OUTPUT BELOW:
finished after doing timePass for 20 seconds
finished after doing timePass for 10 seconds
You are not really creating a callback function but actually calling timePass(20) before everything else on your last line of code.
To pass a callback function you should do something like this:
function timePass(length,callback){
console.log("finished after doing timePass for "+length +" seconds")
if(typeof(callback) == "function")
callback(20);
}
timePass(10,timePass);
This is because you execute the function timePass and then - adding the result as argument number 2.
Explaining what is happening:
First you define new function "timePass", The function printing on the console.
Second you execute timePass(10, /*But here you execute it again*/ timePass(20)).
The function timePass(20) will be executed first because you added ().
() == execute. If you just pass the name of the function, it will be passed as function. When you use () it will be executed and then the result will be passed as argument.
EXAMPLE OF USING CALLBACK
function timePass(length, callbackFunction){
console.log("finished after doing timePass for "+length +" seconds");
// check if the function caller is included callback parameter
// and check if it is function - to prevent errors.
if (callbackFunction && typeof callbackFunction == "function") {
// Execute the callback (timePass)
callbackFunction(20);
}
}
// Here you say, Execute timePass with arg 10, and then call timePass
timePass(10, timePass);
// and now callbackFunction defined above will be == timePass
// You can do also
timePass(10, anotherFunction)
// So another function will be executed after console.log()
USE CASES
Most often callbacks are used while we working with async code.
For example: Jsfiddle
// Imagine we have function which will request the server for some data.
function getData(index) {
// The request - response will took some time
// 0.1s ? 15s ? We don't know how big is the data we downloading.
var data;
// Imagine this is an AJAX call, not timeout.
setTimeout(function() {
// after 30ms we recieved 'server data'
data = 'server data';
},30)
return data;
}
var users = getData('users');
console.log(users); // undefined - because we returned "data" before the AJAX is completed.
/*
So we can change the function and adding an callback.
*/
function getAsyncData(index, callback) {
var data;
// Imagine this is an AJAX call, not timeout.
setTimeout(function() {
// after 30ms we recieved 'server data'
data = 'server data';
callback(data);
},30)
}
getAsyncData('users', function(data) {
console.log(data); // 'server data'
});
// OR
function processData(data) {
console.log(data);
}
getAsyncData('users', processData); // processData also logs 'server data'
basically when the interpreter is looking at this, it will call timepass(20) to evaluate the result (which is nothing as you have no return returning something), which then it tries to pass into the outer function.
i.e.
doFunction( doSomethingElse() );
if doSomethingElse returns 1, it must evaluate that before it can pass that 1 into doFunction.
Fundamentally, you have not actually passed a callback, you have called the function. Perhaps you meant:
callback = function() { somecode; }
target = function(data, callback) { console.log('hi'); callback(); }
target(10, callback);
notice the lack of () i.e. callback not callback()
Related
Is it possible to call a function in JavaScript that calls itself again, and after it calls itself again, finally runs the initial callback function?
I will explain what I mean in code...
//on page load
getProviderNextAppointment(null, function(nextAppointment) {
otherFunction(); //<----- how can I always end up back here, no matter what?
});
//getProviderNextAppointment function
function getProviderNextAppointment(startDate, callback) {
getNextAppointment('provider', startDate, function(data) {
//if provider has schedule
if(!$.isEmptyObject(data.AllProviders)) {
//set provider params
//nextAppointment = data.x
//callback
if(typeof callback === 'function') {
return callback(nextAppointment); //callback from call on page load
}
} else {
if(data.ErrorCode !== 'StartDateTooFarInFuture') {
/*---------->
* this is where we this function calls itself again;
* but when it hits the callback above (provider
* has schedule), or when it hits the callback
* below (last group of appointments), it
* should run the initial callback to
* execute otherFunction()
<----------*/
getProvidersNextAppointment(data.LatestDate);
} else { //hit last group of appointments
if(typeof callback === 'function') {
return callback(null); //callback from call on page load
}
}
}
});
}
I did not include getNextAppointment() function, because it is irrelevant to the question. Just know that it is calling an API that is returning the appointment information, as well as a LatestDate property that we are using as the startDate for the next API call. We are also looking for a response for the ErrorCode property that says it's the end of the results, so that we are not looping forever.
If you need to keep a reference to the initial callback function, then you could just pass it on via the recursive call.
Change the recursive call from this:
getProvidersNextAppointment(data.LatestDate);
to:
getProvidersNextAppointment(data.LatestDate, callback);
Now the nested function context will have a reference to the original callback function, and this could in theory cascade further down the recursion tree until the callback function is finally executed.
I've been reading about async functions in JavaScript and found out that I don't quite understand the following piece of code that comes from here.
Here it is:
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
What I don't understand is where all these results come from.
They are callbacks. A callback is just simply a function which is passed as an argument to another function and is used to do something with the result of some operation done by the function which receives the callback as an argument. You can write your own. A simple example:
function callMe(callback) {
let addition = 2 + 2;
callback(addition);
}
callMe(function(result) {
console.log(result);
});
callMe calls its callback function with the result of 2 + 2. You then receive that result inside the callback function when you use callMe, and you can then write your own custom code to do whatever you want with it.
The beauty of JavaScript is that you already have all you need to test it.
The code you posted references 4 functions (don't forget the failure callback):
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
Those functions are not written. So let's write them:
var failureCallback = function() {
console.log('something went wrong');
}
var doSomething = function(callback) {
window.setTimeout(function() {
var result = Date.now(); // Create some data that will change every time the function is invoked
callback(result);
}, 500);
}
var doSomethingElse = function(res, callback) {
window.setTimeout(function() {
var result = [res]; // all this function really does is put the first argument in an array
callback(result);
}, 500);
}
function doThirdThing(res, callback) {
window.setTimeout(function() {
res.push(Math.PI); // res is supposed to be an array, so we can add stuff to it.
var result = res;
callback(result); // here we could have used res as a value, but I kept it consistent
}, 500);
}
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ', finalResult); // switched to a comma to display properly in the console
}, failureCallback);
}, failureCallback);
}, failureCallback);
To create some asynchronicity I used setTimeout so overall you have to wait 1.5 seconds.
The 3 functions that use a callback function as an argument, simply execute the function they were given. This is absolutely standard in JavaScript where functions are first class objects: you can pass them around as arguments like any other value type.
Javascript is a single threaded language, callbacks are used as a way to control the flow of execution when a asynchronous block of code ends in a non-blocking way. A callback is normally just another function (function B) that is passed into the asynchronous function (function A) to run when function A completes. I.E
doSomething(func) {
// do async code.
// call func
// func()
}
you haven't posted the inner blocks of those functions but i think we can all safely assume "result" is the response from the server passed back into the callback function I.E
doSomething(callback) {
//fetch or ajax or whatever to server store response.
//pass response BACK to callback function
callback(response)
}
I'm having a synchronization and loading issues with some JS modules when the program starts. This error only shows up once at the beginning and then everything works, so it is an obvious sync problem.
The code:
//pyramid of doom
function initGame(){
initWorld(function(){
initPlayer(function(){
initBots(function(){
console.log("Game Loaded!");
update();
})
})
});
}
function initWorld(callback){
world.init(worldParams);
callback&&callback();
}
function initPlayer(callback){
player.init(scene,playerParams,world.getPhysicModel());
callback&&callback();
}
function initBots(callback){
bots.init(scene,botsParams,world.getPhysicModel());
callback&&callback();
}
function update() {
world.update(1/60);
player.update();
bots.update();
}
initGame();
The following is the error I'm getting.
Bots.js:112 Uncaught TypeError: Cannot read property 'mixer' of undefined
at Bots.update (Bots.js:112)
at update (Final.html:160)
What am I doing wrong? How can I synchronize the execution of the init functions?
(What I think that is going on is that the execution of initBots doesn't reach it end before the udpdate function starts to run.)
You can find the Bots.js module in my repository at ( 1 )
In bots.init you execute new THREE.ColladaLoader().load which looks to be asynchronous.
In its callback, you fill your _bots array (self._bots[modelLoaded] = bot;).
However, you execute bots.init() and do not wait for these asynchronous calls to complete before executing the initBots function callback. In the case of initGame execution, this callback executes update(), which in turn executes bots.update(), which tries to access this._bots[i].mixer with i index up to this._botsParams.length, i.e. a pre-defined value that does not account for how many items have been actually filled in _bots array.
Hence your error message: the array has no items yet at some indices, and trying to read a property on undefined throws an error.
Conclusion: common asynchronous issue.
You need to be passing the callbacks into the init functions. Guessing from a brief look at your bots code, they are not expecting to receive callbacks so you might be in for a rebuild.
You can't tell from the outside of an async function if it is done yet!
Equivalent to what you are doing:
let result = undefined
function takeTime () {
setTimeout(function() {
result = 'hello!'
}, 100)
}
function callback () {
console.log(result)
}
function run (callback) {
takeTime()
callback && callback()
}
run(callback) // undefined! takeTime has not finished yet
What you need to be doing:
let result = undefined
function takeTime (callback) {
setTimeout(function() {
result = 'hello!'
callback()
}, 100)
}
function callback () {
console.log(result)
}
function run (callback) {
callback && takeTime(callback)
}
run(callback) // 'hello!', the callback was only called once the takeTime function completed
Lets imagine that I have some code:
var someString = "";
function do1(){
doA();
doB();
}
function doA(){
// some process that takes time and gets me a value
someString = // the value I got in prior line
function doB(){
//do something with someString;
}
What is the correct way to make sure somestring is defined by doB tries to use it? I think this is a situation that calls for a callback, but I'm not sure how to set it up?
Usually, I have solved this problem like following code by callback parameter. However, I don't know this is correct answer. In my case, it's done well.
var someString = "";
function do1(){
doA(doB);
}
function doA(callback){
// some process that takes time and gets me a value
someString = // the value I got in prior line
callback();
}
function doB(){
//do something with someString;
}
I usually write these such that the function can be called with, or without, the callback function. You can do this by calling the callback function only if typeof callback === 'function'. This allows the function which includes the possibility of a callback to be a bit more general purpose. The call to the callback(), obviously, needs to be from within the callback of whatever asynchronous operation you are performing. In the example below, setTimeout is used as the asynchronous action.
var someString = "";
function do1() {
doA(doB); //Call doA with doB as a callback.
}
function doA(callback) {
setTimeout(function() {
//setTimeout is an example of some asynchronous process that takes time
//Change someString to a value which we "received" in this asynchronous call.
someString = 'Timeout expired';
//Do other processing that is normal for doA here.
//Call the callback function, if one was passed to this function
if (typeof callback === 'function') {
callback();
}
}, 2000);
}
function doB() {
//do something with someString;
console.log(someString);
}
do1();
You can, of course, do this without using a global variable:
function do1() {
doA(doB); //Call doA with doB as a callback.
}
function doA(callback) {
setTimeout(function() {
//setTimeout is an example of some asynchronous process that takes time
//Simulate a result
var result = 'Timeout expired';
//Do other processing that is normal for doA here.
//Call the callback function, if one was passed to this function
if (typeof callback === 'function') {
callback(result);
}
}, 2000);
}
function doB(result) {
console.log(result);
}
do1();
function someFunctionA(callback){
var someString = "modify me";
callback(someString);
}
function someFunctionB(someString){
// do something
}
function main() {
someFunctionA(somefunctionB);
}
Why doesn't this function return true?
function test(str) {
window.setTimeout(function() {
if(str == 'ok') {
return true;
}
}, 1000);
}
console.log(test('ok'));
That's not exactly what i want to do.
I have a function nammed test() who does some actions after 1 second.
I want to execute next function, when test() is finished (so after the timeout).
How i can know when test i finished ?
Tracing your code, here's what happens.
test() is invoked.
setTimeout schedules a function to be called 1000 ms later.
test() concludes execution, no return statement was executed, so undefined is returned instead.
about 1000 ms later the scheduled function fires.
The scheduled function returns true to nothing.
In other words, it just doesn't work that way. The JS interpreter does not pause, it continues over the timeout. You cannot pause execution in JS.
Instead you typically use callbacks:
function test(str, callback) {
window.setTimeout(function() {
if (str === 'ok') {
callback(true);
}
}, 1000);
}
// logs 'true' 1000 ms later
test('ok', function(result) {
console.log(result);
});
// logs nothing, callback never fires
test('NOTOK!', function(result) {
console.log(result);
});
This code will do more what you seem to have expected.
It does not return true because the setTimeout call is asynchronous. Also, the return value true in your code comes from an inner function.
The normal way of handling such program flow is to pass a callback to the asynchronous function.
function test(str, callback) {
window.setTimeout(function() {
callback(str == 'ok');
}, 1000);
}
test('ok', function (result) {
console.log(result);
});
The function passed as the second argument to test() will be called when setTimeout executes the code. The argument to the callback function will tell if str is was ok or not.
For starters, settimeout is an asynchronous method, so the actual function test() will have finished and returned before the settimout code runs.
Secondly however, you are only returning true from the settimeout function not the test function, so you will never get anything other than false.
It doesn't return true because asynchronous function setTimeout() will execute after 1000 ms and console.log will execute in normal fashion without waiting of your 'test' function.