Understanding callbacks to run code in desired order - javascript

I was following this tutorial and it was all making perfect sense until...
function first(){console.log('first')}
function second(){console.log('second')}
first()
second()
//first
//second
then:
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
//2
//1
I get all that, but I don't understand how to then implement a callback so that it logs:
//1
//2
in that order.
I know it will be something like:
function first(cb){
// Simulate a code delay
setTimeout( function(){
console.log(1);
cb()
}, 500 );
}
but this blows up. can someone help me see how to use the callback correctly

It should be:
function first(cb){
setTimeout( function(){
console.log(1);
cb(); // <-- calling 'cb' is calling 'second'
}, 500 );
}
function second() {
console.log(2);
}
first(second); // pass 'second' as value of cb
UPDATE:
In case you want to use promises (as you mentionned in your comment), it should be:
function first() {
return new Promise(function(resolve) { // <-- Make the first function returning a promise.
setTimeout(function() {
console.log(1);
resolve();
}, 500);
});
}
function second() {
console.log(2);
}
first().then(function() { // <- 'first' returns a promise so you can .then on it
second();
});

Related

How to execute a function after one function containing Set time out is completed? [duplicate]

How to make it work? pls help.
function first() {
setTimeout((function() {
$('#q').append('first <br>');
}), 1000);
}
function second() {
$('#q').append('second <br>');
}
function third() {
$('#q').append('third <br>');
}
$.when(first()).done(second()).done(third());
first() runs as last function, i need as first
Fiddle here: JSFIDDLE
I am not sure why are you doing this, but if you want to execute them synchronously, you can place the 2nd and 3rd function call inside setTimeout :
function first() {
setTimeout(function() {
$('#q').append('first <br>');
second();
third();
}, 1000);
}
function second() {
$('#q').append('second <br>');
}
function third() {
$('#q').append('third <br>');
}
first();
EDIT:
You can now also try async/await (doesn't support IE) awaiting the timeout promise before executing first second and third. fireEvents is our async function in this example. Notice how since fireEvents has the async keyword before the function that it is able to use the await keyboard. Await keywords allow you to await the finishing of a promise. Here there is a small promise wrapper using the Promise constructor around setTimeout which is returned from the function timeout this timeout function is awaited inside of the async function fireEvents. The commented numbers below show order of the execution. For deeper knowledge on Promise execution order you can read Jake Archibald's wonderful article Tasks, microtasks, queues and schedules.
function timeout (ms) {
return new Promise(res => setTimeout(res,ms));
}
function first () {
// $('#q').append('first <br>');
console.log("first");
}
function second() {
// $('#q').append('second <br>');
console.log("second");
}
function third() {
// $('#q').append('third <br>');
console.log("third");
}
async function fireEvents () {
// 2
console.log("2. before await")
await timeout(1000);
// 4
console.log("4. after await")
first();
second();
third();
}
// 1
console.log("1. started");
fireEvents().then(()=>{
// 5
console.log("5. done")
});
// 3
console.log("3. after fireEvents");
Original Answer
You don't need jquery's deferred when you can use javascript promises instead.
function first() {
return new Promise(function(resolve, reject) {
setTimeout((function() {
$('#q').append('first <br>');
resolve("Stuff worked!");
}), 1000);
});
}
function second() {
$('#q').append('second <br>');
}
function third() {
$('#q').append('third <br>');
}
first().then(second).then(third);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="q"></div>
Another way of executing the last line first().then(second).then(third);
is by making it
first().then(function () {
second();
third();
});
which you can do since you know the second and third functions are synchronous functions unlike the first function which is asynchronous.
EDIT: The reason behind using a javascript promise or in guest271314's answer a jquery defer is because if you wanted to reuse first but call something besides first or second after it's done in a different part of your code you could just write something to the effect of
first().then(function () {
fourth();
fifth();
});
And you would be writing that without changing the function for first. Promises and deferreds make async code more reusable.
Try utilizing $.Deferred() within first , return $.Deferred() jQuery promise when setTimeout completes , call second , third within .done()
function first() {
var d = new $.Deferred();
setTimeout((function() {
$('#q').append('first <br>');
d.resolve()
}), 1000);
return d.promise()
}
function second() {
return $('#q').append('second <br>');
}
function third() {
return $('#q').append('third <br>');
}
$.when(first()).done([second, third]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id='q'></div>
jsfiddle http://jsfiddle.net/hqphbhx3/1/
If you want to isolate the functions, try this. You pass in a callback to the first function, and when the timer times out, that callback is called. In that callback you can call second() and third().
function first(callback) {
setTimeout(function() {
$('#q').append('first <br>');
callback();
}, 1000);
}
function second() {
$('#q').append('second <br>');
}
function third() {
$('#q').append('third <br>');
}
first(function(){
second();
third();
});
A few problems: Your first function (and the rest of them, for that matter) are not returning promises, so you can't use done. If you were using promises, done would seal the promise and not allow you to chain another done call. For this setup, you would be better off nesting your function calls like:
function first() {
setTimeout((function() {
$('#q').append('first <br>');
second();
}), 1000);
}
function second() {
$('#q').append('second <br>');
third();
}
function third() {
$('#q').append('third <br>');
}
Try this..
function first() {
setTimeout((function() {
$('#q').append('first <br>');
second();
third();
}), 1000);
}
function second() {
$('#q').append('second <br>');
}
function third() {
$('#q').append('third <br>');
}
first();
try:
function start() {
setTimeout((function () {
$.when(first()).done(second()).done(third());
}), 1000);
}
function first() {
$('#q').append('first <br>');
}
function second() {
$('#q').append('second <br>');
}
function third() {
$('#q').append('third <br>');
}
start();
for me this worked unexpectedly, I just added an arrow function as third parameter and it was executed right after setTimeout finished
setTimeout(() => {
first();
second();
},
1000,
() => {
third()
}
);

Callback on the function JS

I'm trying to make this work, what am I doing wrong?
I want to be able to do some stuff when function one is completed.
function one() {
// do stuff
}
function main() {
//script
//script
one(function() {
// do some stuff when "one" is completed
console.log("one is completed");
});
}
Why this doest fire a callback? (no log entry in the console)
You need to pass the callback as an argument and call it like normal function
function one(a, b, fn) {
// do staff
if (fn) {
fn()
}
}
function main() {
//script
//script
one(5, 6, function() {
// do some stuff when "one" is completed
console.log("one is completed");
}
}
Cause one does not expect a callback, therefore it will be ignored and never called back.
function one(callback) { // <- take a callback
callback(); // <- call back the callback "callback"
}
You need to pass the callback function inside the one() function. Then you need to call that function:
const one = (cb) => {
console.log('in one()');
cb();
}
const main = () => {
one(() => {
console.log('one() is completed');
});
}
main();
OUTPUT:
in one()
one() is completed

Method execution with the help of callback in javascript

I know 2 will be console.logged first and then 1. Is there any way, maybe with callbacks, I can show 1 first and then 2?
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
Put second()'s call in the setTimeout:
function first(){
// Simulate a code delay
setTimeout( function(){
console.log(1);
second();
}, 500 );
}
function second(){
console.log(2);
}
first();
You could also bypass first, second and setTimeout completely:
console.log(1);
console.log(2);
function second(){
console.log(2);
}
function first(cb){
// Simulate a code delay
return setTimeout( function(){
console.log(1);
cb();
}, 500 );
}
first(second);
Solve it by promise a clan and elegant way:
function second() {
console.log("test2", 2);
}
function first() {
var promise = new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("test1", 1);
resolve();
}, 500);
});
return promise;
}
first().then(function () {
second();
});
don't use timeout call in first function. or you can use promises
for better understanding of event loop callback execution order read this article
link. this article explains execution order , which get priority among promise , timeout etc
Hope it will help

How to ensure to call function after all other functions

I have 4-5 JavaScript functions which calls ajax and respond after sometime, but for example I am giving example of 3 functions without ajax code.
Here I want to ensure that func3 will call after two other functions func1 and func2.
func3();
func1();
func2();
function func1(){
setTimeout(function(){
console.log("func1");
}, 2000);
}
function func2(){
setTimeout(function(){
console.log("func2");
}, 3000);
}
function func3(){
setTimeout(function(){
console.log("func3");
}, 1000);
}
I want total time would be 4 seconds. func1 and func2 would run simultaneously in 3 seconds and then func3 in 1 second.
Call them at the end of the func before?
func3();
function func1(){
console.log("func1");
func2();
}
function func2(){
console.log("func2");
}
function func3(){
console.log("func3");
func1();
}
Edit 1:
func1();
function func1(){
setTimeout(function(){
console.log("func1");
func2();
}, 1500);
}
function func2(){
setTimeout(function(){
console.log("func2");
func3();
}, 1500);
}
function func3(){
setTimeout(function(){
console.log("func3");
}, 1000);
}
Just a quick primer on Promises:
A promise is an object that basically says, "This work isn't done yet, but I'll let you know when it is."
When you create a Promise, you can attach callback functions using .then(). When the promise is resolved - that is to say, it's work is finished - all of the callbacks will be executed. You can also attach callbacks with .fail() or something similar, and these will be executed if the Promise is rejected.
In your case, you might do something like:
func1().then(func2).then(func3);
function func1(){
var p = new Promise();
setTimeout(function(){
console.log("func1");
p.resolve();
}, 2000);
return p;
}
function func2(){
var p = new Promise();
setTimeout(function(){
console.log("func2");
p.resolve();
}, 3000);
return p;
}
function func3(){
var p = new Promise();
setTimeout(function(){
console.log("func3");
p.resolve();
}, 1000);
return p;
}
In addition, most Promise Libraries have a .whenAll() type function. This takes multiple Promises and calls its .then() callbacks when all promises have completed. So you could do:
whenAll(func1(), func2()).then(func3);
If you are in an environment where you can use EcmaScript6, there is a built in Promise library. Read this MDN article for information on that library.
Otherwise, I strongly recommend jQuery's promise library.
Note: The above code is just psuedocode. Read the documentation to see how to actually implement the Promises in those frameworks.
I made it as I want, like this. But I don't know its good of bad practice, I am not aware of promise and get some answer's but those were not working.
start = 0;
func1();
func2();
function func1(){
setTimeout(function(){
console.log("func1");
start++;
if(start==2){
func3();
}
}, 2000);
}
function func2(){
setTimeout(function(){
console.log("func2");
start++;
if(start==2){
func3();
}
}, 3000);
}
function func3(){
setTimeout(function(){
console.log("func3");
}, 1000);
}
Note : first function func1 prints in 2 seconds func2 in 1 second because 2 already gone, and then func3 in 1 second total 4 seconds cheers :)
let promises = [];
let ajaxCall = new Promise((resolve, reject) => {
console.log('ajaxCall');
setTimeout(() => {
resolve();
},1000);
});
let fn1 = new Promise((resolve, reject) => {
console.log('fn1');
ajaxCall.then(() => {
resolve();
});
});
let fn2 = new Promise((resolve, reject) => {
console.log('fn2');
ajaxCall.then(() => {
resolve();
});
});
promises.push(fn1);
promises.push(fn2);
Promise.all((promises)).then(() => {
console.log('fn3');
});
Hope this helps

Wait for function to complete before executing next command

I'm creating a game where user writes a function that will execute and do stuff such as move a robot/rotate etc.
I've got this code :
function move(){
setTimeout(function(){
console.log("Log 1,5");
}, 3000);
return true;
}
function anotherMove(){
setTimeout(function(){
console.log("Log 2,5");
}, 2000);
return true;
}
function action(){
console.log("Log 1");
move();
console.log("Log 2");
anotherMove();
console.log("Log 3");
}
action();
Imagine move/anotherMove as robot movement and console.logs as calculations between those moves. Is there anyway to output logs correctly : 1 -> 1,5 -> 2 -> 2,5 (currently its 1 -> 2 -> 3 -> 1,5 -> 2,5) so basically that console.log waits for move/anotherMove to complete before executing these logs.
I can change move/anotherMove structure (it will be canvas animation) but I need action() structure stay as it is...
Thanks a lot !
Promises do just what you're looking for. These are available in ES6, or there are several libraries, for example, Q.
You'll start wrapping timeout in a promise...
function timeout(ms) {
return new Promise(function (resolve, reject) {
setTimeout(resolve, ms);
});
}
Now that timeout function will return a promise, which can be chained with another promise using the function then(). So, for example, your move() function can be improved as ...
function move(aString, aDelay) {
return timeout(aDelay).then( () => {
console.log(aString);
true;
});
}
The action function almost writes itself...
function action() {
console.log("Log 1");
return move("Log 1.5", 3000).then(() => {
console.log("Log 2");
move("Log 2.5", 2000);
}).then(() => {
console.log("Log 3");
});
}

Categories

Resources