I've been unable to find a simple example of a javascript callback pattern for my purpose and an answer to the following question would be very helpful.
Supposing I've 2 functions which each display an alert:
function hello1() {
setTimeout(function(){
alert("hello1");
}, 500);
}
function hello2() {
alert("hello2");
}
if I'm using this function,
function saythehellos()
{
hello1();
hello2();
}
the alert "hello2" will display first followed by the alert "hello1"
How can I change the function saythehellos() using a callback pattern so that the alert "hello1" is displayed first followed by the alert "hello2"?
As per quetion, you can define a callback pattern as per the following, define callback function as an argument.
function hello1(callback) {
setTimeout(function(){
alert("hello1");
callback();
}, 500);
}
function hello2() {
alert("hello2");
}
hello1(hello2);
In ES6 a special syntax to work with promises in a more comfortable fashion, called async/await. It’s surprisingly easy to understand and use. you can also use it. In behind the scene, async/await work as callback
Edited as per request:
You can do it by the third function(saythehellos) as per the following chain.
function hello1(callback) {
setTimeout(function(){
alert("hello1");
callback();
}, 500);
}
function hello2(callback) {
alert("hello2");
callback();
}
function saythehellos(callback) {
hello1(function() {
hello2(function() {
callback();
});
});
}
saythehellos(function(){alert('all done')});
You could use ES7's async/await syntax with a promise. In your hello1() method you can return a promise which will alert() and then resolve to indicate that your hello1 method is complete. Then saythehellos() will wait for hello1() to resolve (as we are using the await keyword) and then it will continue to execute hello2():
function hello1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
alert("hello1");
resolve();
}, 500);
});
}
function hello2() {
alert("hello2");
}
async function saythehellos() { // make async as we want to use await within this method
await hello1();
hello2();
}
saythehellos();
Alternatively, if you're looking for something a little more browser compatible, you can use the .then callback on the returned promise from hello1() (which is essentially what async/await is doing under the hood). The .then callback will be fired when the returned promise has resolved:
function hello1() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
alert("hello1");
resolve();
}, 500);
});
}
function hello2() {
alert("hello2");
}
function saythehellos() {
hello1().then(function(result) {
hello2();
});
}
saythehellos();
The simple callback way is:
function hello1(hello2Callback) {
alert("hello1");
hello2Callback && hello2Callback();
}
hello1(function() {
alert("hello2");
});
I hope this will help you. The callback function is a function that is passed as an argument. So, when calling hello1(), I am passing a complete function definition. This argument is called callback function.
The Promise is a new efficient and clean way on handling callbacks. You can check Javascript Promise over Google.
Simple approach to achieve this:
function Hello1(){
setTimeOut(onTimeOutRaise,500)
}
function onTimeOutRaise(){
alert("Hello1");
Hello2();
}
function Hello2(){
alert("Hello2")
}
Here "onTimeOutRaise" itself a callback.
Related
I'm a bit new to JavaScript and i can't figure out why the printing order of the following code is Noam and then Amit and only them.
can someone clarify it?
function rc(){
console.log('Assaf');
}
function thenCall(){
console.log('Amit');
}
function myPromise(){
return Promise.resolve(function(){
console.log('Yarden');
rc();
});
}
myPromise().then(function(){thenCall()});
console.log('Noam');
Promise.resolve takes a result which is passed to the then. It does not call the function. Notice the callback to .then.
function rc(){
console.log('Assaf');
}
function thenCall(){
console.log('Amit');
}
function myPromise(){
return Promise.resolve(function(){
console.log('Yarden');
rc();
});
}
myPromise().then(function(fn){
console.log(fn); // notice
thenCall()
});
console.log('Noam');
The function inside Promise.resolve should be executed as it will wait for a result to return:
function rc(){
console.log('Assaf');
}
function thenCall(){
console.log('Amit');
}
function myPromise(){
return Promise.resolve(function(){
console.log('Yarden');
rc();
}());
}
myPromise().then(function(){thenCall()});
console.log('Noam');
Let's divide the question by the people you're trying to log
Noam
Noam is printed first, because there is no async process in the code. You do use a Promise but it instantly executes the resolve method.
Amit
When Promise.resolve gets invoked, the function in the .then method will be executed. Therefore Amit gets printed in the console correctly.
Yarden and Assaf
Promise.resolve immediately resolves a new Promise and calls therefore the .then method immediately. The argument given to Promise.resolve is the value that will be passed as an argument to the .then method.
To create an actual Promise that either resolves or rejects based on some logic, this should get you started:
var a = true;
function myPromise() {
return new Promise(function (resolve, reject) {
console.log('first');
if (a) {
return setTimeout(function () {
resolve('value_to_pass_to_then');
}, 1000);
}
return reject('value_to_pass_to_catch');
});
}
myPromise()
.then(function (val) { console.log('second'); })
.catch(function (val) {})
The Yarden function is what the promise returned by myPromise() resolves to. But you aren't doing anything with the resolve value:
myPromise().then(function(/* resolve value would go here */){thenCall()});
The value a promise resolves to is the first argument of the function passed to .then. But you don't have an argument there. If you wanted to run that function, you would have to use it as an argument and then call it explicitly (which would in turn call the function that prints Assaf):
function rc() {
console.log('Assaf');
}
function thenCall() {
console.log('Amit');
}
function myPromise() {
return Promise.resolve(function() {
console.log('Yarden');
rc();
});
}
myPromise().then(function(yardenFn) {
thenCall();
yardenFn();
});
console.log('Noam');
I'm working on a way to chain a set of 3 ajax calls per variable against an array of data with some delay in between.
Taking into account this answer.
I'm trying to update the code to achieve the following:
Add a delay in the b() and c() function
Pass a variable from a() to b() and from b() to c()
Is there a way I can pass a variable a() would generate to b() without using global variables? If not that's fine, I'd just like to know.
And how exactly can I get b() to be delayed for several seconds before processing c()? I would assume adding in a setTimeout would work as it's waiting for the promise before it starts c(), but this is not the case.
jsfiddle
function a(user, pass) {
return $.post('/echo/json/', {}, function(re){
console.log(1);
});
}
function b() {
setTimeout(function() {
return $.post('/echo/json/', {}, function(re){
console.log(2);
});
}, 3000);
}
function c() {
console.log(3);
}
var data = [{u: 'au', p: 'ap'}, {u: 'bu', p: 'bp'}];
var counter = 0;
function main() {
if(counter < data.length) {
$.when(a(data[counter].u, data[counter].p).then(b).then(c)).done(function(){
counter++;
main();
})
}
}
main();
To ensure that c() isn't executed until after the timeout code has been called, create your own promise and return it from the b() function. You should wrap the setTimeout function in this promise, and call the resolve(res) method to notify the .then() functions watching the promise, passing an object representing the data or body of the response.
function b(dataFromA) {
return new Promise((resolve, reject) => {
setTimeout(function() {
return $.post('/echo/json/', {}, res => {
let dataToB = res;
console.log(2);
resolve(dataToB);
});
}, 3000);
});
}
Note that b() now accepts data that can be passed from the response of the a() promise. You can manipulate this data inside the b(res) function or in the promiseFromA.then(res => { // ... Your promise callback code }); before calling b(res).
setTimeout as used in function b is not a promise. i will find some docs to site and post shortly but here is what i see.
to use a promise you need to call a promise method, setTimeout is not a promise. it is only a delay. it has to do with the event loop in javascript or in the javascript runtime to be more correct. there is some good stuff over here --> https://github.com/getify/You-Dont-Know-JS/tree/master/async%20%26%20performance
also .then only works to resolve a promise
getify really breaks it down but i would start with the javascript event loop
Asynchronous calls are an inherent part of javascript, and using callbacks is often an elegant tool to handle these calls.
However, I am not quite sure how is the branching of code following an asynchronous operation decided. For example, what would happen with the following code?
function f(callback) {
value = some_async_call();
if (value) {
callback(value);
}
return(value);
}
What would happen here? From my short JS experience, return would send back an undefined value. But suppose that value returns true from the asynchronous call, would the callback be called with the right value or with an undefined value?
In other words, is there a rule regarding which operations are executed immediately after the async call, and which are deferred until the value is returned?
What have I tried before asking
SFTW for branching asynchronous calls in javascript, but found nothing canonical or decisive.
update: added a practical difference between the 3 different approaches at the bottom
let's assume some_async_call(); is defined as an async function: async function some_async_call() { ... }
what this function returns is a Promise, which means that value is now a promise: value.then( function(result) { } )
when i translate this into code:
async function some_async_call() {
if (theMoonIsInTheRightPosition)
return Fetch('/api/data/') // this returns a promise as well.
return false;
}
i can now do 2 things:
function parentFunction(callback) {
var promise = some_async_call();
promise.then( callback );
return ...; // you can't "return" the value of an async call synchronously, since it is a promise.
}
or:
async function asyncParentFunction( callback ) {
var value = await some_async_call();
if (value)
callback( value );
return value;
}
however, this transforms the parent-function into an async function as well, which means the immediate return value of that function... is a promise as well.
Long story short:
You either use callbacks to flow through your asynchronous functions, or promises, or async/await
callbacks
function doStuff(callback) {
// do asynchronous stuff
var result = 100;
callback(result); // once you're done with stuff
}
doStuff( function(data) { console.log('Im done!', data); } );
promises
function doStuff() {
return new Promise(function(resolve, reject) {
// do asynchronous stuff
var result = 100;
resolve(result);
});
}
doStuff.then(function(data) { console.log('Im done!', data); });
async/await
function doStuff() {
return new Promise(function(resolve, reject) {
// do asynchronous stuff
var result = 100;
resolve(result);
});
}
(async function() { // async/await only works in async functions.
var data = await doStuff();
console.log('Im done!', data);
})();
as you can see: promises and async/await use the same mechanism and are really worth reading into.
a practical example of the difference between the three:
callbacks
function fetchUserWithPosts(userId, callback) {
fetchUser(userId, function(user) {
fetchPostsByUserId(userId, function(posts) {
callback({
user: user,
posts: posts
});
});
});
}
promises
function fetchUserWithPosts(userId) {
return Promise.all([
fetchUser(userId),
fetchPostsByUserId(userId)
]).then(function(result) {
return {
user: result[0],
posts: result[1]
};
});
}
async/await
async function fetchUserWithPosts(userId) {
return {
user: await fetchUser(userId),
posts: await fetchPostsByUserId(userId);
};
}
You are correct, undefined will be returned. You execute your logic after asynchronous operation you should pass your callback into that function. You are trying to use code in synchronous manner and async/await comes to the rescue. Assuming that some_async_call returns Promise you can write:
async function f(callback) {
var value = await some_async_call();
if (value) {
callback(value);
}
return value;
}
In this case your function will return Promise of value and also will be asynchronous. Read more here.
And even more you don't need to pass a callback. You can await your function in client code and execute callback from there.
Regarding branching, the only way you can branch without using async/await is to make some_async_call accept a callback that accepts the value as parameter:
function f(callback) {
some_async_call(function(value) {
if (value) {
callback(value);
}
});
}
And to reiterate once again there is no way to return a value from async method except Promise. Or Observable in RxJS.
I'd like to run the function that consists of:
if condition is solved
1)add class
2)sleep 4 sec then remove class
3)then stop running function using return.
function sleep(time) {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
function playGame() {
if (counter === 3) {
Promise.resolve().then(function () {
message.classList.add('winner');
sleep(2500).then(function () {
message.classList.remove('winner');
});
});
return;
}
...
}
If I run this code, function returning immediately of course. How do I add return to the promise chain.
This should work:
Promise.resolve()
.then(function () {
message.classList.add('winner');
})
.then(sleep(2500))
.then(function() {
message.classList.remove('winner');
});
This should be self-explanatory. Feel free to ask more questions as needed.
EDIT : Oooops it seems that I answered this one too quickly. You can never postpone a "return" statement in javascript. In your case, your code, or mine executes immediately, and the return of the enclosing function is called immediately, and the execution goes back to the event loop. Then, the first then() of the promise is called, etc...
Since you can't postpone the return of the function, you use callbacks, or better, Promises, to chain events:
function playGame() {
return Promise.resolve() // note the return !
.then(function () {
message.classList.add('winner');
})
.then(sleep(2500))
.then(function() {
message.classList.remove('winner');
});
}
...then
playGame()
.then(function() {
// this code is called after playGame's Promise has been executed
});
// this code is called when playGame ends, ie immediately, and before any promises code
To put it differently: once you begin to have asynchronous code (through callbacks or promises), every further code needs to be driven by promises, too.
how to run next function after first done with setInterval?
for example:
step1();
step2();
setInterval(step1, 1000).done(function() {
setInterval(step2, 1000).done( /* next step */);
});
please help me with solution!
Edit: This is an old answer. Now you can achieve this using promises also but the code will be slightly different.
If you don't want to use a promise you can use a simple flag to achieve such a thing. Please see example below:
var flag = true;
function step1() {
console.log('title');
}
function step2() {
console.log('subtitle');
}
function wrapper() {
if(flag) {
step1();
} else {
step2();
}
flag = !flag;
}
setInterval(wrapper, 30000);
If you want to chain functions on completion you can use callback functions.
Example:
function first(callback) {
console.log('Running first');
if (callback) {
callback();
}
}
function second() {
console.log('Running second function');
}
first(second);
The first function checks if a callback is used and then runs it. If there is no callback function nothing happens. You can chain functions this way.
You can also use anonymous functions.
first(function () {
console.log('This function that will run after the first one);
});
If you use setTimeout() you can't be sure whether the previous function has completed. A better way would be to use promises.
Understanding Promises
I hope I understood your question right. Good luck!
First of all setInterval can not be done by itself, it will fire infinitely if you not clear it with clearInterval.
But if you have some async action inside your function and whant to wait for it and then call another function you may just promisify it like Avraam Mavridis suggested.
function step1() {
var deferred = $.Deferred();
setTimeout(function () {
alert('I am step 1');
deferred.resolve();
}, 1000);
return deferred.promise();
}
function step2() {
alert('I am step 2');
}
step1().done(step2);
JsFiddle