What's the purpose of callback function if code skips macrotasks? - javascript

Recently, I've tried to understand callback functions in JavaScript, however, this concept is still far away from my understanding. I have code like this:
function exampleFunc(callback) {
console.log("Starting...");
setTimeout(() => {
console.log("Logged after 3 secs.");
}, 3000);
callback();
}
function displayMessage() {
console.log("Log it!");
}
exampleFunc(() =>
{
console.log("Further code.");
});
displayMessage();
I've expected that after calling exampleFunc(), program will wait 3 seconds, and then call the callback and rest of code. But instead, the sequence of code is:
Starting...
Further code.
Log it!
Logged after 3 secs.
Why does it happen? I've expected that program will output "Starting", then wait and log "Logged after 3 secs.", then go to callback and output "Further code", and in the end, "Log it!".

Calling a setTimeout does not cause further execution of the code in that function to delay. setTimeout schedules a timeout, then continues executing the rest of the code in the function immediately.
You need to call callback inside the setTimeout callback, so that it runs only after the 3 seconds are up.
You also need to put the call of displayMessage inside the callback passed to exampleFunc.
function exampleFunc(callback) {
console.log("Starting...");
setTimeout(() => {
console.log("Logged after 3 secs.");
callback();
}, 3000);
}
function displayMessage() {
console.log("Log it!");
}
exampleFunc(() => {
console.log("Further code.");
displayMessage();
});

Related

Why this callback is not running properly?

I'm a noob in coding. I'm really sorry about that. I have this code here....
function fn1(){
setTimeout(function(){console.log("fn1")},3000)
}
function fn2(){
console.log("fn2")
}
function fn3(callback, callback2){
if(callback){
console.log("It works!")
} else {
callback2
}
}
fn3(fn1(),fn2())
The objective here is to call Function3(fn3) console.log ("It works") only after Function1(fn1) runs ok. If Function1 fails, it should return Function2.
The output that I'm getting is:
fn2
fn1
I know it is extremely wrong but I don't know WHAT is wrong.
I know that there are other stuff (that I still don't know - like promises, async, await and stuff) but I wanna learn this method first.
Could you guys help me?
Yes, you are right. This is a huge nonsense.
Correct me if I'm wrong: you want the console to log "It works!" after the timeout set in the fn1. Then you'll need the fn1 to tell somehow that it finished it's execution so it can run the console.log. If you want to use the callback approach, then the fn1 could be something like:
function fn1(callback, errorCallback) {
setTimeout(function() {
try {
callback();
} catch (error) {
errorCallback();
}
}, 3000);
}
And the fn3 could go like this:
function fn3() {
fn1(function() { console.log('It works!'); }, fn2);
}
You can call fn3 just with fn3().
To be honest, as simple as these functions are, there's no way the fn2 is called as there are no errors in the code and no human interaction. Well, maybe if there's no standard output available to do the console.log, but I don't know if that's even possible.
As you can see, in the fn3 we are passing two functions as parameters to fn1. The first is an anonymous function that shows the text in the output. The second function is the fn2, that should be run in case of error. No parenthesis here when passing them as parameters as we want to pass functions, not the result of calling them (which would be undefined in this example).
The fn1 receives those functions as parameters and runs them in different situations. The first, when the timeout has finished, and the second if there's any error when calling the callback.
You have to pass references on the functions as parameters of fn3 (you currently call them and pass their result).
Also, in the fn3, you need to call the function.
Your code fixed below (if I correctly understood what you were looking for):
function fn1(next) {
setTimeout(next, 3000);
}
function fn2() {
console.log("fn2")
}
function fn3(callback, callback2){
function itWorks() {
console.log('it works!');
}
try {
callback(itWorks);
}
catch (e) {
callback2();
}
}
fn3(fn1, fn2); // Will display "it works!" after 3 seconds
fn3(undefined, fn2); // Will display "fn2" because trying to call an undefined function
I understood that you want to call f3 after the f1 is called successfully and call the f2 when f1 fails? If yes then see this
function fn3(){
console.log("It Works!");
}
function fn2(){
console.log("fn2");
}
function fn1(){
const promisePass = new Promise((resolve, reject) => {
setTimeout(resolve, 100)}); //Emulate success
const promiseFail = new Promise((resolve, reject) => {
setTimeout(reject, 100);});//Emulate fail
promisePass.then(function(){
fn3();
}).catch(function(){
fn2();
});
promiseFail.then(function(){
fn3();
}).catch(function(){
fn2();
});
}
fn1(); //<<-- calling f1 now will pass and fail the setTimeout method and then
// fn2 and fn3 are called accordingly

Loading modules JS

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

Execute asynchronous javascript code every X seconds

How to execute asynchronous js code (written in node.js) every X seconds and ensure that the new execute/call won't be started before the callback (success, error) from asynchronous function is executed. Code example:
asyncFunc(function(successData){
// do something with successData
}, function(errorData){
// do something with errorData
});
setInterval comes to my mind firstly, but I think it won't ensure what I want, if the callback doesn't execute inside interval, it will go to the queue.
EDIT: To simplify case, repeat async function call 1 second after its callback finishes.
You can use setTimeout like this:
(function loop() {
asyncFunc(function(successData){
setTimeout(loop, X);
}, function(errorData){
// If you still want to continue:
setTimeout(loop, X);
});
})(); // execute immediately
This will start the delay when the async call triggers the callback.
Consider abstracting the problem with a re-usable method that'll allow you to specify the function to call, the interval at which it's called, and the callbacks to invoke:
function repeatAsync(func, interval, success, error) {
(function loop() {
func(
() => {
success();
setTimeout(loop, interval);
},
() => {
error();
setTimeout(loop, interval);
}
);
})(); // invoke immediately
}
If you want the chain of calls to be broken on error, replace the second argument to func with just error, i.e. func( () => { ... }, error)

JavaScript Multiple Callback Function

I have been trying to figure out the Callback function feature in Javascript for a while without any success. I probably have the code messed up, however I am not getting any Javascript errors, so I supposed the syntax is somewhat correct.
Basically, I am looking for the getDistanceWithLatLong() function to end before the updateDB() begins, and then make sure that ends before the printList() function begins.
I have it working with a hardcoded "setTimeout" call on the functions, but I am overcompensating and forcing users to wait longer without a need if the Callback stuff would work.
Any suggestions? Below is the code:
function runSearchInOrder(callback) {
getDistanceWithLatLong(function() {
updateDB(function() {
printList(callback);
});
});
}
To accomplish this, you need to pass the next callback into each function.
function printList(callback) {
// do your printList work
console.log('printList is done');
callback();
}
function updateDB(callback) {
// do your updateDB work
console.log('updateDB is done');
callback()
}
function getDistanceWithLatLong(callback) {
// do your getDistanceWithLatLong work
console.log('getDistanceWithLatLong is done');
callback();
}
function runSearchInOrder(callback) {
getDistanceWithLatLong(function() {
updateDB(function() {
printList(callback);
});
});
}
runSearchInOrder(function(){console.log('finished')});
This code outputs:
getDistanceWithLatLong is done
updateDB is done
printList is done
finished
wouldn't this work:
function callback(f1, f2) {
f1();
f2();
}
As for passing arguments, be creative.
function1 = (callback1, callback2, callback3) => {
setTimeout(() => {
console.log("function 1 timed out!");
callback1(callback2, callback3);
}, 1500);
}
function2 = (callback1, callback2) => {
setTimeout(() => {
console.log("function 2 timed out!");
callback1(callback2);
}, 1500);
}
function3 = (callback1) => {
setTimeout(() => {
console.log("function 3 timed out!")
callback1()
}, 1500);
}
function4 = () => {
setTimeout(() => {
console.log("function 4 timed out!")
}, 1500);
}
function1(function2, function3, function4);
Just pass down the callbacks from the first function and execute each one, passing down the rest.
OUTPUT
function 1 timed out!
function 2 timed out!
function 3 timed out!
function 4 timed out!
In JavaScript, everything is an object, including functions. That is why you are able to pass callbacks as parameters - you are passing a function as if it were any other object.
In each function declaration, you need to run the callback.
function runSearchInOrder(callback) {
...
callback();
}
function getDistanceWithLatLong(callback) {
...
callback();
}
function updateDB(callback) {
...
callback();
}
Then your code posted above should work.

Return true and setimout

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.

Categories

Resources