How to make an async then? - javascript

Basically I am trying to play around to understand more of async/await and promise in JS. I'm trying to make Hello comes in between finished! and third finish!!. So the best guess is, making second then asnyc and await for console.log('Hello'). I've tried both ways below but both are not working as expected.
Approach A
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(() => {
setTimeout(async function(){
await console.log("Hello"); }, 3000); //async/await at setTimeout level
}).then(() => {
console.log('third finish!!')
})
Approach B:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(async () => { //async/await at thenlevel
await setTimeout(function(){
console.log("Hello"); }, 3000);
}).then(() => {
console.log('third finish!!')
})

You need the second section to be a Promise, and return it from the .then so that it's properly chained between the first and the third. setTimeout doesn't return a Promise, you have to explicitly construct a Promise instead:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(() => {
return new Promise(resolve => {
setTimeout(function(){
console.log("Hello");
resolve();
}, 1000);
});
}).then(() => {
console.log('third finish!!')
})
Or, using await, use await new Promise followed by the same Promise construction and the setTimeout:
let promise = new Promise((res, rej) => {
res();
});
promise.then(() => {
console.log('finished!')
}).then(async() => {
await new Promise(resolve => {
setTimeout(function() {
console.log("Hello");
resolve();
}, 1000);
});
}).then(() => {
console.log('third finish!!')
})

Another approach is to write an asynchronous setAsyncTimeout function (this hasn't been thoroughly tested, may need tweaks):
async function setAsyncTimeout(callback, interval) {
return new Promise( (resolve, reject) => {
setTimeout(() => {
try {
let inner = callback()
if (inner && inner.then) {
inner.then(resolve, reject)
} else {
resolve(inner)
}
} catch(e) {
reject(e)
}
}, interval)
})
}
Testing via your example:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then( setAsyncTimeout(function(){
console.log("Hello"); }, 3000);
}).then(() => {
console.log('third finish!!')
})
Testing via your example (with another promise):
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(async () => { //async/await at thenlevel
await setAsyncTimeout(function(){
console.log("Hello");
return setAsyncTimeout(() => console.log("world"), 3000)
}, 3000);
}).then(() => {
console.log('third finish!!')
})
Cleaner example:
let promise = new Promise((res,rej)=>{
res();
});
promise.then(() => {
console.log('finished!')
}).then(() => {
return setAsyncTimeout(() => { console.log("Hello"); }, 3000)
}).then(() => {
console.log('third finish!!')
})

Related

Proper use of async JS to ensure function calls wait for previous functions to complete (resolve?)

Trying to learn proper async/await JavaScript to run functions in sequence when an early function in the sequence would be delayed (using setTimeout to simulate). I'm not getting the expected results (still getting "first", "second", "this should run first?" - see code).
What am I missing? Do I have the wrong idea about this?
Thanks in advance!
const zeroFunction = () => {
setTimeout(() => {
return new Promise((resolve) => {
console.log("This should run first?");
resolve();
});
}, 2000)}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first");
resolve();
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second");
resolve();
})
}
async function fnAsync() {
await zeroFunction();
await firstFunction();
secondFunction();
}
fnAsync();
zeroFunction is currently returning undefined implicitly, not a Promise. Inverse the wrapping of the setTimeout and Promise constructor and it should work as expected.
const zeroFunction = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log("This should run first?")
resolve()
}, 2000)
})
}
const firstFunction = () => {
return new Promise((resolve) => {
console.log("first")
resolve()
})
}
const secondFunction = () => {
return new Promise((resolve) => {
console.log("second")
resolve()
})
}
async function fnAsync() {
await zeroFunction()
await firstFunction()
secondFunction()
}
fnAsync()

How can i synchronize these 3 promise-based functions?

How can i synchronize these 3 promise returning functions (For example in other function)? I want to get following output -> Start -> (2secs)..2..(3secs)..3..(4secs)..4 -> End. I've tryed Generators, but my output wasn't like that (Probably i did something wrong)
function resolveAfter2Seconds() {
new Promise(resolve => {
setTimeout(() => {
resolve('resolved 2');
console.log('2')
}, 2000);
});
}
function resolveAfter3Seconds() {
new Promise(resolve => {
setTimeout(() => {
resolve('resolved 2');
console.log('3')
}, 3000);
});
}
function resolveAfter4Seconds() {
new Promise(resolve => {
setTimeout(() => {
resolve('resolved 2');
console.log('4')
}, 4000);
});
}
First, change the functions to return their promises. For example:
function resolveAfter2Seconds() {
return new Promise(resolve => { // <------ added return statement
setTimeout(() => {
resolve('resolved 2');
console.log('2')
}, 2000);
});
}
Then either chain the promises together
resolveAfter2Seconds()
.then(() => resolveAfter3Seconds())
.then(() => resolveAfter4Seconds());
Or use async/await syntax:
async function exampleFunction() {
await resolveAfter2Seconds();
await resolveAfter3Seconds();
await resolveAfter4Seconds();
}
You might want to try chaining to get the sequential output:
resolveAfter2Seconds()
.then(() => resolveAfter3Seconds())
.then(() => resolveAfter4Seconds())
PS. Don't forget to make those functions return promises.

Refactoring Promise to Async/wait. Why I got undefiened?

I have the code on Promise:
function one() {
return new Promise((rs,er)=>{
console.log('start');
new Promise((rr,err)=>{setTimeout(()=>{console.log('after 3 sec');rr()},3000)})
.then( sd => {
console.log('endLong');
rs();
})
});
}
one().then(_ => one()).then(_ => one());
And as a result I get syncronized code.
But when I refactoring it to async/wait
async function one() {
console.log('start');
await longtime();
console.log('endLong');
}
async function longtime() {setTimeout(()=>{console.log('after 3 sec');},3000);}
one().then(_ => one()).then(_ => one())
then I got:
start
endLong
start
endLong
start
endLong
PromiseĀ {<resolved>: undefined}
after 3 sec
after 3 sec
after 3 sec
What's wrong?
You need longtime to return a promise. A setTimeout alone does not mean anything to promise-based async/await:
async function one() {
console.log('start');
await longtime();
console.log('endLong');
}
const longtime = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('after 0.5 sec');
resolve();
}, 500);
});
one()
.then(_ => one())
.then(_ => one())
setTimeout does not return a promise. An async function should return a promise that's resolved with the value.
function longtime() {
return new Promise(resolve => {
setTimeout(() => {
console.log('after 3 sec');
resolve();
}, 3000);
});

Catching promise errors from a loop

I need to call multiple promises inside a for loop, but it gives me unhandled promise exception during each run. The way to solve this is to return the second promise, this way the last catch would be executed and it would work without errors, but - second and more iterations would not be executed.
const doFirstThing = () => {
return new Promise((resolve, reject) => {
setTimeout(() => (resolve(['a', 'b', 'c'])), 1000);
});
}
const doSecondThing = () => {
return new Promise((resolve, reject) => {
setTimeout(() => (reject('test')), 500); // reject here
});
}
doFirstThing()
.then(results => {
results.forEach(result => {
doSecondThing(result)
.then(() => console.log(result, 'done'));
});
})
.catch(error => console.log(error));
How can I deal with this?
To prevent unhandled promise exception chain .catch() to lat .then(); substitute using Promise.all() and .map() for .forEach()
const doFirstThing = () => {
return new Promise((resolve, reject) => {
setTimeout(() => (resolve(['a', 'b', 'c'])), 1000);
})
}
const doSecondThing = (r) => {
return new Promise((resolve, reject) => {
setTimeout(() => (reject('test')), 500); // reject here
})
}
doFirstThing()
.then(results => {
return Promise.all(results.map(result => {
return doSecondThing(result)
}));
})
.then((result) => console.log(result, 'done'))
.catch(error => console.log(`err:${error}`));

About Node.js Promise then and return?

I'm confused about Promise!
I use Promise then without return like this:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
new Promise((resolve, reject) => {
//Time-consuming operation, for example: get data from database;
setTimeout(() => {
resolve(2)
}, 3000);
}).then((v11) => {
console.log("v11");
})
}).then((v2) => {
console.log("v2")
});
I get this result v1 v2 v11.
Then, I use another way of writing, Like below:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 3000)
}).then((v11) => {
console.log("v11");
})
}).then((v2) => {
console.log("v2")
});
I get another result v1 v11 v2.
Maybe, There is another case:
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1");
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 3000)
}).then((v11) => {
console.log("v11");
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 4000)
}).then(() => {
console.log("v12")
})
})
}).then((v2) => {
console.log("v2")
});
I get this result v1 v11 v12 v2
I can't understand the second return I want to know why I get this result?
It will be easier to understand the control flow if you actually print the values of the resolved promises and not only the names of the variables:
Version 1
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
new Promise((resolve, reject) => {
//Time-consuming operation, for example: get data from database;
setTimeout(() => {
resolve(2)
}, 3000);
}).then((v11) => {
console.log("v11:", v11);
})
}).then((v2) => {
console.log("v2:", v2)
});
Version 2
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 3000)
}).then((v11) => {
console.log("v11:", v11);
})
}).then((v2) => {
console.log("v2:", v2)
});
Version 3
new Promise((resolve, reject) => {
resolve("1");
}).then((v1) => {
console.log("v1:", v1);
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 3000)
}).then((v11) => {
console.log("v11:", v11);
return new Promise((resolve, reject) => {
setTimeout(() => {resolve(2)}, 4000)
}).then((v12) => {
console.log("v12:", v12)
})
})
}).then((v2) => {
console.log("v2:", v2)
});
Now you can see what gets passed to the callbacks:
Result 1
v1: 1
v2: undefined
v11: 2
Result 2
v1: 1
v11: 2
v2: undefined
Result 3
v1: 1
v11: 2
v12: 2
v2: undefined
Explanation
As you can see when in the .then() handlers you don't return a promise, it acts as if you returned an already resolved promise with value undefined - like if you did:
return Promise.resolve(undefined);
and thus the next .then() handler can be called immediately.
If, on the other hand, you return a promise that is not resolved yet, then the next .then() handler will not be invoked immediately but only after that returned promise gets resolved.
And that explains the order of execution that is different when you don't return a promise - and what happens is as if an already resolved promise got returned implicitly for you.
function one() {
return new Promise((resolve,reject) => {
setTimeout(function () {
console.log("one 1 ");
resolve('one one');
}, 2000);
});
}
function two() {
return new Promise((resolve,reject) => {
setTimeout(function () {
console.log("two 2 ");
resolve('two two');
}, 10000);
});
}
function three(){
setTimeout(function () {
console.log("three 3 ");
}, 5000);
}
one().then((msg) => {
console.log('one : ', msg);
return two();
}).then((msg) => {
console.log('two :', msg);
return three();
}).then((msg) => {
console.log('three :', msg);
})
.catch((error) => {
console.error('Something bad happened:', error.toString());
});
console three show undefined because three not parse resolve

Categories