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

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);
});

Related

Why do async await and Promise.all have the same running time?

I have created three Promises as follows and awaited them, expecting them to take 6000 milliseconds:
let PromiseOne = new Promise(resolve => {
setTimeout(() => {
resolve('Promise One');
}, 2000);
});
let PromiseTwo = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Two');
}, 2000);
});
let PromiseThree = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Three');
}, 2000);
});
(async() => {
console.time();
let ResponseOne = await PromiseOne;
let ResponseTwo = await PromiseTwo;
let ResponseThree = await PromiseThree;
console.log(ResponseOne, ResponseTwo, ResponseThree);
console.timeEnd();
})();
But, I have received an unexpected console message as follows.
Promise One Promise Two Promise Three
default: 2.004s
As I know, each await has 2000ms of running time. But, It doesn't.
In this case, what is the difference between my code above using async/await and the code below using Promise.all?
let PromiseOne = new Promise(resolve => {
setTimeout(() => {
resolve('Promise One');
}, 2000);
});
let PromiseTwo = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Two');
}, 2000);
});
let PromiseThree = new Promise(resolve => {
setTimeout(() => {
resolve('Promise Three');
}, 2000);
});
(() => {
Promise.all([PromiseOne, PromiseTwo, PromiseThree]).then(res => {
console.log(res);
});
})();
In both cases, you're constructing all the Promises immediately. After the declaration of PromiseThree ends, for both, you're left with 3 promises, each of which resolves after 2 seconds. No matter what happens later in the script, each of those will resolve after 2 seconds.
If you use Promise.all, all of the promises will have resolved after 2 seconds.
If you use async/await, the first one you wait for will take 2 seconds to resolve. At that same time, the other two will have resolved, so doing await PromiseTwo and await PromiseThree will take next to no time at all - so, still a total of 2 seconds.
// at this point, each promise has been created and each will take 2 seconds
(async() => {
console.time();
// 2 seconds for the below line
let ResponseOne = await PromiseOne;
// after 2 seconds, all have resolved; below line takes no time at all
let ResponseTwo = await PromiseTwo;
// same as above
let ResponseThree = await PromiseOne;
It'd be different if you constructed the other promises after awaiting the previous ones - in which case they'd run in serial as you're expecting with await.
let makePromise = () => new Promise(resolve => {
setTimeout(() => {
resolve();
}, 2000);
});
console.log('starting');
(async () => {
console.time();
await makePromise();
await makePromise();
await makePromise();
console.timeEnd();
})();

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.

How to make an async then?

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!!')
})

Understanding Promise and Await

I am just trying to understand how Promises and Async-Await work.
I want this to resolve by logging 1, 2, 3 in that order. Currently it logs 1, 3, 2.
I know the Promise doesn't really make sense here but in my program it has other uses so that needs to stay. The route from Caller function to Test also needs to stay (If need be you can change these but just know that they are there for a reason)
My question is how do I wait for the Caller function to resolve?
Here is my code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
Test();
}
console.log('1');
Caller();
console.log('3');
I have tried what I understand, which is to make the Caller() function await the Test Promise, but that of course makes the Caller() function async and therefore we still get 1, 3, 2
async function Caller() {
await Test();
}
Is there maybe some way to use await without making the function async?
You can only await a function that returns a promise (well, not quite true, if it doesn't return a promise it creates a promise that resolves instantly)
You can only await when you are inside an asynchronous function
function test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
async function caller() {
console.log('1');
await test();
console.log('3 (this is blocked awaiting the promise');
}
caller()
console.log("This is not blocked because caller is async");
This is a very straightforward, simple way of doing what you ask.
The await keyword can only be used inside functions
defined with async.
function test(ms) {
return new Promise((resolve, reject) => setTimeout(resolve, ms))
}
async function caller() {
console.log(1, ' - caller() started');
await test(2000).then(() => {
console.log(2, ' - test() resolved')
});
console.log(3, ' - delayed until "test()" has resolved');
return 4;
}
// wait for "caller()" to resolve
caller().then((result) => {
console.log(result, " - caller() finished")
});
console.log(5);
Here's a good article by Google which expands on the subject:
Async functions - making promises friendly.
Cite source.
here is how you could use functions like this:
function sleep(ms) {
return new Promise(r => {
setTimeout(() => r(), ms);
});
}
(async () => {
console.log(1);
await sleep(1000); // 1s
console.log(2);
await sleep(2000) // 2s
console.log(3)
})();
The previous answers are all correct but I just feel like this answer makes more sense. It is more accurate to the original question's code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
return Test();
}
(async() => {
console.log('1');
await Caller();
console.log('3');
})();

Categories