How to call a function after completion of another function using callback? - javascript

function one(){
console.log(1);
}
function two(callback){
setTimeout(()=>{
console.log(2);
},2000);
callback();
}
two(one);
While I am running this code, 1 is displaying first and then 2 because 2 is taking 2 second time to display. Suppose if there is an api instead of console.log(2) in function two which is taking 2 second to respond, so How I can call function one after completion of function two using callback(); which I can do in this case if I use callback() inside setTimeout function but what if there is an api where I am not using setTimeout and it's taking 2-3 second?

Even if there is an api call which takes time to resolve, you can still use a callback at the same way you just did with the setTimeout example.
Alternatively, use a Promise:
function two(callback) {
new Promise(res => {
setTimeout(() => {
res();
}, 2000);
}).then(callback)
}
or using async/await syntax:
async function two(callback) {
await new Promise(res => {
setTimeout(() => {
res();
}, 2000);
})
callback();
}

you can use sync function like this
function two() {//this function takes 2 seconds
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
function one(){
console.log("one");
}
async function asyncCall() {
console.log('calling');
const result = await two();
one()
// expected output: 'resolved'
}
asyncCall();
here is reference link

You can use Promises:
function one(){
console.log(1);
}
function two(){
return new Promise((resolve, reject) => {
setTimeout(()=>{
console.log(2);
resolve()
},2000);
})
}
two().then(() => one())

Put callback(); inside setTimeout:
function one(){
console.log(1);
}
function two(callback){
setTimeout(()=>{
console.log(2);
callback();
},2000);
}
two(one);

Related

Refactor nested promises to a chain of promises

I have simplified this problem. I have 3 functions which I want to run with a 2 second delay between each. The following code is working:
$.when(one()).done(function () {
$.when(delay(2000)).done(function () {
$.when(two()).done(function () {
$.when(delay(2000)).done(function () {
$.when(three()).done(function () {
console.log('finished');
});
});
});
});
});
function delay(ms) {
var waitForDelay = new $.Deferred();
setTimeout(function () {
waitForDelay.resolve().promise();
}, ms);
return waitForDelay.promise();
}
function one() {
console.log('one');
return new $.Deferred().resolve().promise();
}
function two() {
console.log('two');
return new $.Deferred().resolve().promise();
}
function three() {
console.log('three');
return new $.Deferred().resolve().promise();
}
However when I try to refactor it, it no longer waits for the delayed amounts of time:
one().done(delay(2000)).done(two).done(delay(2000)).done(three).done(function () {
console.log('finished');
});
How can I refactor to chain these promises rather than nesting them? I want to use jQuery for older browser compatibility.
My advice would be to not use jQuery's weird promise-like data structures at all.
Have your functions return an actual Promise (either explicitly or by making them async functions) and await each step in the chain.
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
// an async function implicitly returns a promise
const one = async () => {
console.log("one");
}
// or you can return one manually
const two = () => {
console.log("two");
return Promise.resolve();
}
const three = async () => {
console.log("three");
}
// await each step in an async function (an async IIFE in this case)
(async () => {
await one();
await delay(2000);
await two();
await delay(2000);
await three();
console.log("finished");
})();
You can also use .then() if you prefer that style
// Convenience function so you don't repeat yourself
const waitTwoSeconds = () => delay(2000);
one()
.then(waitTwoSeconds)
.then(two)
.then(waitTwoSeconds)
.then(three)
.then(() => {
console.log("finished");
});
If you must use jQuery, it doesn't really look much different
function delay(ms) {
var d = $.Deferred();
setTimeout(d.resolve, ms);
return d.promise();
}
function one() {
console.log("one");
return $.Deferred().resolve().promise();
}
function two() {
console.log("two");
return $.Deferred().resolve().promise();
}
function three() {
console.log("three");
return $.Deferred().resolve().promise();
}
function waitTwoSeconds() {
return delay(2000);
}
one()
.then(waitTwoSeconds)
.then(two)
.then(waitTwoSeconds)
.then(three)
.then(function() {
console.log("finished");
});
<!-- Note jQuery 1.8 was the first to have chainable deferreds -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
I've used .then() instead of .done() because the latter does not chain and using $.when() is unnecessary when .then() is available.
Taking inspiration from Phil's answer, here is a solution compatible with older browsers.
First, change the delay() function to return a function:
function delay(ms) {
return function() {
var waitForDelay = new $.Deferred();
setTimeout(function () {
waitForDelay.resolve().promise();
}, ms);
return waitForDelay.promise();
}
}
All other functions stay the same as in the question.
Finally replace the .done()s with .then()s to make them chain:
one().then(delay(2000)).then(two).then(delay(2000)).then(three).then(function () {
console.log('finished');
});

Make the function call synchronous

function first(){
console.log("1")
}
function second(){
new Promise ((resolve,reject)=>{
setTimeout(function(){
console.log("2")
resolve();
} ,0);
})
}
function third(){
console.log("3")
}
async function run(){
first();
await second();
third();
}
run();
Need to make the function call sync to get final output as 1,2,3 i tried creating the promise and use async await but that didnt help any other way
Pack the setTimeout into a promise and resolve in setTimeout,
Use async await for that promise in order for that to run consecutively
function first() {
console.log("1")
}
function second() {
return new Promise(res => {
setTimeout(function() {
console.log("2");
res()
}, 0)
})
}
function third() {
console.log("3")
}
async function run() {
first();
await second()
third();
}
run();

Javascript understanding promises

I've been using async with NodeJS, but I'm trying to understand the basic of promises in JavaScript and I'm having issues with it.
I created the code below for testing.
function first() {
// Simulate a code delay
return new Promise(function(resolve) {
setTimeout(function() {
console.log(1);
}, 500);
});
}
function second() {
console.log(2);
}
first().then(second());
It should print '1' first, but it is printing '2' in the console first. Why is it happening?
Thanks
Two things:
first().then(second()) invokes second() immediately and passes its return value as the argument to then. You want to pass in the function itself, not its return value:
first().then(second); // no parens on second
And you're never resolving the first promise:
return new Promise(function(resolve) {
setTimeout(function() {
console.log(1);
resolve(); // <-- without this the promise is never resolved
}, 500);
}
);
With those issues addressed it works as you'd intended:
function first() {
// Simulate a code delay
return new Promise(function(resolve) {
setTimeout(function() {
console.log(1);
resolve(); // <-- without this the promise is never resolved
}, 500);
});
}
function second() {
console.log(2);
}
first().then(second);
There are a 2 problems in your code :
Your function first() returns a promise, but it isn't a promise in itself, so you cannot use the .then attribute on it.
You're not resolving anything in your 1st promise, you're just console.logging something, which is not something you can "wait" for.
What you're looking for is more something like this :
let first = new Promise((resolve) => {
setTimeout( function() {
console.log("1");
resolve(true); //you return your response, for example a boolean
}, 500)
})
function second(){
console.log("2");
}
first.then(response => {
//this is usually where you do something with the response
second();
});
Use Async Await
(as ray write) In new Promise() You must return resolve() or reject()
You can also use await:
function first() {
return new Promise(res => {
console.log(1);
return setTimeout(res, 500);
})
}
function second() {
console.log(2);
}
(async () => {
await first();
second();
})();

Am I nesting the function correctly?

I have little doubt, I have let say 5 or more js functions each calls C# functions Via Ajax calls doing various task like(fetching data from the database, validating it, calculations, saving it back to The database etc).
I am calling the function using Nested jQuery $.when(function1()).then(function2()) and so on. I want function one to fully complete before two and two before the third one and so one.... there are some dependency between these functions...
My Code example Like: (My Approach)
$(document).ready(function () {
$.when(one()).then(
$.when(two()).then(
$.when(three()).done(alert('three done')).then(
$.when(four()).then(
five()
).done(alert('All Finished Up'))
)
)
)
});
function one() //eg List 1000 records from Db
function two() //Update Some
function three() //validate Changes
function four() //save Changes
function five() // Some Other Task then
Now my question is simple I know rather than calling sequentially like
$(document).ready(function(){
one();
two();
three();
four();
five();
});
I used above nesting pattern (My Approach)... Is that good approach coding-wise and performance wise? Is there any more efficient approach than this?
Alternatively, you can run all of those calls in parallel to get a faster return
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function one(mode) {
await sleep(1000);
console.log(`${mode} : one() finished`);
}
async function two(mode) {
await sleep(3000);
console.log(`${mode} : two() finished`);
}
async function three(mode) {
await sleep(3000);
console.log(`${mode} : three() finished`);
}
async function four(mode) {
await sleep(4000);
console.log(`${mode} : four() finished`);
}
async function five(mode) {
await sleep(5000);
console.log(`${mode} : five() finished`);
}
async function runInSerial() {
await one('serial');
await two('serial');
await three('serial');
await four('serial');
await five('serial');
}
async function runInParallel() {
await Promise.all([
one('parallel'),
two('parallel'),
three('parallel'),
four('parallel'),
five('parallel'),
]);
}
$(document).ready(function () {
runInSerial().then(() => console.log('serial : all done!'));
runInParallel().then(() => console.log('parallel : all done!'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
There is: if you want to only support browsers that support ES6, you can simply use the async/await syntax, as the jQuery Promises return a native Promise object anyway:
// Dummy async operation
function sleep(t) {
return new Promise(resolve => setTimeout(resolve, t));
}
$(document).ready(function() {
run().then(() => console.log('all done'));
});
// Run all your async functions sequentially
async function run() {
await one();
console.log('one done');
await two();
console.log('two done');
}
async function one() {
return sleep(500);
}
async function two() {
return sleep(500);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Execute javascript function after previous one finishes

I have the function "showElement" that has a setTimeout. How can I make that the calls to the function in the eventListener of the 'btnSend' execute one right after the other one?
I tried with .then() but didn't work.
document.getElementById('btnSend').addEventListener('click', e => {
e.preventDefault();
result = validateInputs(email, subject, message);
if(result) {
showElement(document.getElementById('formGroupSpinner'), 2000);
showElement(document.getElementById('formGroupSuccessImg'), 2000);
resetForm();
}
});
//expects an html element and a number representing miliseconds. Shows the html element for that amount of time.
function showElement(element, mSeconds) {
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout( () => {
element.classList.remove('d-block');
element.classList.add('d-none');
}, mSeconds);
}
Both functions execute at the same time.
There's many different approaches to this but I would suggest using a Promise like this:
document.getElementById('btnSend').addEventListener('click', e => {
e.preventDefault();
var result = validateInputs(email, subject, message);
if(result){
showElement(document.getElementById('formGroupSpinner'), 2000).then(()=>{
return showElement(document.getElementById('formGroupSuccessImg'), 2000);
}).then(()=>{
resetForm();
});
}
});
//expects an html element and a number representing miliseconds. Shows the html element for that amount of time.
function showElement(element, mSeconds) {
return new Promise((resolve, reject) => {
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout( () => {
element.classList.remove('d-block');
element.classList.add('d-none');
resolve();
}, mSeconds);
});
}
Basically, the function after the .then() only gets executed once you called the resolve();.
Alternatively you could also use a callback or async / await.
you could use a callback to execute other instructions after the function has ended:
//First you add a param "callback" to the function
function showElement(element, mSeconds, callback) {
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout( () => {
element.classList.remove('d-block');
element.classList.add('d-none');
//Then you ask if the callback function is present and call it
if(callback && typeof callback === "function") callback();
}, mSeconds);
}
//Then use it in your event like this:
document.getElementById('btnSend').addEventListener('click', e => {
e.preventDefault();
result = validateInputs(email, subject, message);
if(result) {
showElement(document.getElementById('formGroupSpinner'), 2000, () => {
showElement(document.getElementById('formGroupSuccessImg'), 2000);
resetForm();
});
}
});
You can do this by using Promise. You have to wrap your showElement() function into a promise and call the promise resolver once setTimeout fires.
Then your calling code can pipe your the promises together with then:
showElement(document.getElementById('formGroupSpinner'), 2000).then(() => {
showElement(document.getElementById('formGroupSuccessImg'), 2000).then(() => {
resetForm();
});
});
However, this quickly leads to callback hell.
You can avoid this by using async/await.
You mark your function as async, then you can use await within it to wait for the promises to resolve before continuing to the next one:
await showElement(document.getElementById('formGroupSpinner'), 2000);
await showElement(document.getElementById('formGroupSuccessImg'), 2000);
resetForm();
Here is a working demo:
document.getElementById('btnSend').addEventListener('click', async e => {
e.preventDefault();
await showElement(document.getElementById('formGroupSpinner'), 2000);
await showElement(document.getElementById('formGroupSuccessImg'), 2000);
});
function showElement(element, mSeconds) {
return new Promise((resolve, reject) => {
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout(() => {
element.classList.remove('d-block');
element.classList.add('d-none');
resolve();
}, mSeconds);
});
}
.d-none {
display: none;
}
.d-block {
display: block;
}
<button id="btnSend">Send</button>
<div id="formGroupSpinner" class="d-none">Spinner</div>
<div id="formGroupSuccessImg" class="d-none">Success image</div>
The simplest way to do what you want is simply changing the second showElement to 4000 instead of 2000.
That way one will have a timeout of 2 seconds and the other 4 seconds.
To make a promise chain, you first have to have a promise.
function showElement(element, mSeconds) {
return new Promise(function(resolve,reject){
element.classList.remove('d-none');
element.classList.add('d-block');
setTimeout( () => {
element.classList.remove('d-block');
element.classList.add('d-none');
resolve();
}, mSeconds);
}
}
Then you can use showElement().then(/*something here */)

Categories

Resources