async function doThings() {
async function timer () {
setTimeout(() => {
console.log('timer!')
}), 1000
}
async function printer () {
console.log('printer!')
}
await timer()
await printer()
}
doThings()
I thought making the function async made it return a promise and await made it wait. Why does printer() finish first?
Your timer function doesn't work because setTimeout does not return a promise that could be awaited. You will need to promisify it manually:
// set a default of 1500
function timeout(ms=1500) {
return new Promise(resolve => setTimeout(resolve, ms));
};
async function printer() {
console.log('printer!');
};
async function doThings() {
await timeout(1000); // time in ms
await printer();
};
doThings();
The word “async” before a function means one simple thing: a function always returns a Promise. Other values are wrapped in a resolved Promise automatically.
Now when we use don't return Promise from async function, then javascript interpreter automatically returns resolved Promise, so that is the reason await on timer function got the resolved Promise and interpreter went ahead with the execution, but there is a setTimeout still going on. So we have to return a Promise from timer function, and resolve it inside setTimeout function like below.
async function doThings() {
async function timer() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`timer!`);
resolve();
}, 1000)
});
}
async function printer() {
console.log('printer!')
}
await timer()
await printer()
}
doThings()
All I can see is timer () and printer () functions are async functions but there is no await used in them, and this makes the async keyword unfunctional.
Related
I'm trying to understand difference between these 3. Callbacks & Promises are clear but I don't get the usage of async/await. I know it is the syntactic sugar of promises but what I've tried didn't work. I'm sharing the piece of code I've tried to understand all this...
I've tried with an array
var array = [1,2,3];
and 2 functions
get() executes in 1 sec & console the array
post(item) executes in 2 sec & push a new item in the array
Now, what I want to get is that the post method should execute first & get after it so that the result on the console should be [1,2,3,4] not [1,2,3]
CALLBACK
function get() {
setTimeout(() => console.log(array), 1000);
}
function post(item, callback) {
setTimeout(() => {
array.push(item);
callback();
}, 2000);
}
function init() {
post(4, get);
// returns [1,2,3,4] ✅
}
It works fine but in case of too many callbacks, code will be messier... So,
PROMISE
function get() {
setTimeout(() => console.log(array), 1000);
}
function post(item) {
return new Promise((resolve, reject) => setTimeout(() => {
array.push(item)
resolve();
}, 2000));
}
function init() {
post(4).then(get);
// returns [1,2,3,4] ✅
}
Ok with much cleaner code. But still multiple then calls... Now,
Async/Await
function get() {
setTimeout(() => console.log(array), 1000);
}
function post(item) {
setTimeout(() => {
array.push(item)
}, 2000);
}
async function init() {
await post(4);
get();
// returns [1,2,3] ❌
await post(4);
await get();
// returns [1,2,3] ❌
post(4);
await get();
// returns [1,2,3] ❌
}
Much more cleaner version but neither way, it worked... I've also tried this (convert both functions (post & get) to async and call with then)
async function get() {
setTimeout(() => console.log(array), 1000);
}
async function post(item) {
setTimeout(() => {
array.push(item)
}, 2000);
}
async function init() {
post(4).then(get);
// returns [1,2,3] ❌
}
But still of no use. So I'm totally confused about this feature (i.e. async/await). Please elaborate on this very example. And also please tell me about Promise.resolve & Promise.all in this same context! Thanks
async and await are tools to manage promises
await post(4);
Here you are waiting for the promise returned by post to be resolved.
function post(item) {
setTimeout(() => {
array.push(item)
}, 2000);
}
However, post does not return a promise, so it does nothing useful.
You had a working implementation of post with a promise before. So use that:
function post(item) {
return new Promise((resolve, reject) => setTimeout(() => {
array.push(item)
resolve();
}, 2000));
}
Your attempts with async and await do not use anything that resolves a promise after a delay. As it stands, all the async functions you have defined, return a promise that immediately resolves.
You'll want to use a utility function that you can often use. It returns a promise that resolves after a given number of milliseconds, using setTimeout:
// utility function
let delay = ms => new Promise(resolve => setTimeout(resolve, ms));
let array = [1, 2, 3];
async function get() {
await delay(1000);
console.log(array);
}
async function post(item) {
await delay(1000);
array.push(item)
}
async function init() {
await post(4);
await get();
}
init();
console.log("wait for it...");
Similar to what you did in PROMISE.
Wrap post setTimeout in a promise and return it.
call resolve inside the body of the settimeout.
function post(item) {
return new Promise((resolve)=>{
setTimeout(() => {
array.push(item)
resolve()
}, 2000);
})
}
then you can use it like that :
async function init() {
await post(4);
get();
}
I have the following codes:
function test1() {
test2.execute();
}
I am trying to use await inside an async function to make test1() execute first:
it("title", async () => {
await test1();
await firebase.assertSucceeds(true);
})
But somehow the function test1() does not execute before firebase.assertSucceeds(true). test1() returns a callback. I tried to use the callback, and it does not help either.
function test1() {
test2.execute().then(() => {
return;
});
}
it("title", async () => {
let x = await test1();
await firebase.assertSucceeds(true);
})
Still synchronous. what did I do wrong here?
In your first snippet you are awaiting for test1 which returns void (nothing), for the await to work it should be applyed to a promise, you acheive that either by returning test2.execute() which returns a Promise :
function test1() {
return test2.execute();
}
or by making test1 async and await for test2 to finish executing :
async function test1() {
await test2.execute();
}
ps: an async function returns a resolved promise with the return as the resolution value so for example :
async function test(){
return 2;
}
is translated under the hood to this:
function test(){
return Promise.resolve(2);
}
A function has to return a Promise if you want to await it.
For example:
function test1() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("I'm done")
}, 500)
})
}
Notice, in the firebase documentation, that assertSucceeds only takes a promise as it's one and only argument. So consider passing it a promise that always resolves if that's what you're going for to begin with.
await firebase.assertSucceeds(Promise.resolve())
I can't seem to wrap my head around async await, let's say I want to process one item of an array at a time, with a 1 second delay:
myfunction() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
for (const item of this.myarray) {
this.dosomething(item).then((res: string) => {
setTimeout(() => {
await this.final_thing_before_the_next_item.push(res);
}, 1000);
});
}
}, 200);
}
Where would I put the "async"?
Stackblitz demo
You can put an async inside the setTimeout:
myfunction() {
setTimeout(async () => {
for (const item of this.myarray) {
await this.wait(1000);
console.log(item);
}
});
}
wait(timer: number): Promise<void> {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), timer);
});
}
In a simplified form, await is syntax sugar for consuming promises. The following snippets are pretty much equivalent:
doSomethingAsync().then(value => {
console.log('it finished', value);
});
const value = await doSomethingAsync();
The caveat is that if you want to use await, you need to mark the function as async. I will assume you want to have a 1s delay after full completion. Your code might look something like this:
function wait() {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async function processItems(items) {
for (const item of items) {
const res = await this.doSomething(item);
// This isn't processed until doSomething completes.
const other = await this.doFinalThing(res);
// This isn't run until doFinalThing completes.
await wait(1000);
// The loop now continues after waiting 1s.
}
}
you marked this as angular, so I'm going to say, consider rxjs...
// imports
import {timer, from, concat} from 'rxjs'
import {switchMap, delay} from 'rxjs/operators'
// wait 200 ms
timer(200).pipe(
// switch
switchMap(() => {
// map array into streams
const obs$ = this.myArray.map(i => {
// from promise, do whatever
return from(this.dosomething(i)).pipe(
// switch again, to do final thing, again from promise
switchMap(res => from(this.finalThing(res))),
// delay 1s
delay(1000)
)
});
return concat(...obs$); // execute one after the other
})
).subscribe(v => console.log('values 1 by 1, spaced 1s apart', v))
If you want to process one asynchronous operation at a time, you could do the following:
// "wait" for a 1000ms before resolving the Promise
const wait = (ms = 1000) => {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
};
// array of asynchronous operations
const promises = Array.from({ length: 4 }).map((_, idx) =>
Promise.resolve(idx)
);
async function main() {
const data = [];
for (let item of promises) {
const result = await item;
await wait(1000);
data.push(result);
console.log("result", result);
}
console.log("final data", data);
}
main();
If I understand your question (and code sample) correctly, you basically want to
Sleep 200 ms
Iterate over a list of items. For each item you want to:
Call a function, passing the current item to it and getting a response in return.
Pause for 1 second.
Call a second function, passing it the response
To do that you need a sleep() function that returns a promise that will resolve when the specified time has elapsed:
function sleep(ms = 1000) {
const p = new Promise( (resolve, reject) => {
setTimeout(() => resolve());
});
return p;
}
Having that, you need an async function to do the actual work. It has to be async because that is what lets it await other things:
async function process_items( items, delayInMs = 1000 ) {
for ( item of items ) {
const res = await doSomething( item, delayInMs );
await sleep(delay);
await doSomethingElse( res );
}
}
As you can see from the above bit of code, the advantage of using async/await over callbacks or promise chains is that it gives you a rather more succinct and declarative syntax.
Then you can wrap it all up in another async function:
async function myfunction() {
await sleep(200);
await process_items( this.myarray, 1000 );
}
Marking a function as async does two things: it
Enables the use of await within that function, and
Converts the function into a function returning a promise, regardless of what its ostensible return value is.
If you take this function:
function foo() {
return 1;
}
and mark it as async:
async function foo() {
return 1;
}
it is (more or less) as if you had changed to to read:
function foo() {
return Promise.resolve(1);
}
The easiest way, without looking at the specifics of your code is before myFunction ie async myFunction(). I see 'this' being used so I imagine this is a method of some object/class in which case that would be one way to go about it.
The code below logs 'hello world' once in a second as expected.
function moveOneStep() {
return new Promise((res, rej) => {
setTimeout(() => {
res(console.log('Hello world!'))
}, 1000)
})
}
async function main() {
await moveOneStep();
await moveOneStep();
await moveOneStep();
await moveOneStep();
}
Considering the return value of an async function corresponds to what is returned from resolve function in promises, why doesn't the code below output the same result, but instead logs all the 'hello world's at once:
async function moveOneStepAsync() {
setTimeout(() => {
return console.log('Hello world!');
}, 1000);
}
async function main() {
await moveOneStepAsync();
await moveOneStepAsync();
await moveOneStepAsync();
await moveOneStepAsync();
}
That's because setTimeout does not return promise to await it in your main function. setTimeout itself executes synchronously. It adds to an event loop the callback that is passed as an argument to execute in time that is mentioned.
Also in this code return of your callback means nothing as callback with be run in 1 sec and the returned value will go nowhere.
async keyword tells you that functions returns promise and could have awaitable code in it. So as there is not await in your code it then looks like
function moveOneStepAsync() {
setTimeout(() => {
return console.log('Hello world!');
}, 1000);
return Promise.resolve();
}
So your await in main will await one event loop tick to go to the next "step"
Read about setTimeout, event loop, and what await expects to understand it more in-depth
You do not return anything to the function, you return back to the internal setTimeout function, and that does not do anything with that value. Calling setTimeout does not return a promise, it rather returns a timer immeadiately. And therefore all the moveOneStepAsync calls execute immeadiately, the timers get set, and fire after one second.
I have been going over async/await. I trying few simple examples but unable to understand flow of async and await . In below code
function wait(ms) {
return new Promise(r => setTimeout(function() {
console.log('Hello');
}, ms));
}
async function GetUser() {
await wait(5000);
console.log('world');
}
GetUser();
Why is the message "world" not logged? Only "Hello" prints.
You should call the resolver.
function wait(ms) {
return new Promise(r => setTimeout(function(){console.log('Hello'); r();},
// ^^^ this
ms));
}
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You need to resolve it. So call r()
function wait(ms) {
return new Promise(r => setTimeout(function() {
console.log('Hello');
r()
}, ms));
}
async function GetUser() {
await wait(3000)
console.log('world');
}
GetUser()
Here wait() method returns a Promise, the function of await keyword is to stop code execution until the returned Promise by wait() is resolved.
So the code snippet in question, without using async/await will be as below. Note that the resolve function is not yet invoked here. Hence, once the snippet is executed only Hello will get printed in the console.
// First code snippet
function wait(ms) {
return new Promise(r => setTimeout(function () {
console.log('Hello');
}, ms));
}
function GetUser() {
return wait(1000)
.then(() => {
console.log("World")
})
.catch((err) => {
console.log(err);
})
}
GetUser()
Code snippet when r() is invoked. Here, once the snippet is executed Hello and World both are printed in the console.
// Second code snippet
function wait(ms) {
return new Promise(r => setTimeout(function () {
console.log('Hello');
r();
}, ms));
}
function GetUser() {
return wait(1000)
.then(() => {
console.log("World")
})
.catch((err) => {
console.log(err);
})
}
GetUser()
The reason why the second code snippet works, has to do with how Promise is implemented in JS.
Handler function/functions attached to a promise with the help of .then() are invoked only when the promise is resolved.
Code snippet when resolve method is not invoked inside the executor function i.e, when the Promise is not resolved. Here, only code inside setTimeout is invoked and not the handlers.
function wait(ms) {
return new Promise(r => setTimeout(function () {
console.log('Hello');
}, ms));
}
const promiseReturnedByWaitMethod = wait(2000);
// Multiple handlers can be added to a promise reference, which are executed when the asynchronous operation is completed.
// adding first handler
promiseReturnedByWaitMethod.then(() => {
console.log("First handler!!")
});
// adding second handler
promiseReturnedByWaitMethod.then(() => {
console.log("Second handler!!")
});
Code snippet when resolve method is invoked inside the executor function i.e, when the Promise is resolved.
function wait(ms) {
return new Promise(r => setTimeout(function () {
console.log('Hello');
r();
}, ms));
}
const promiseReturnedByWaitMethod = wait(2000);
// Multiple handlers can be added to a promise reference, which are executed when the asynchronous operation is completed.
// adding first handler
promiseReturnedByWaitMethod.then(() => {
console.log("First handler!!")
});
// adding second handler
promiseReturnedByWaitMethod.then(() => {
console.log("Second handler!!")
});