awaiting an async function - javascript

I don't really know when/how to use async & await. For example I have this function that returns a promise:
async function fn1(){
return await fetch('localhost:3000')
}
Now I have two options:
use .then
fn1.then((result) => {
console.log(result)
})
use await
const data = await fn1()
console.log(data)
I'd prefer the second approach but this would make me wrap it inside an async function which I have to await or use .then to use it.
I've seen some tutorials that use async/await and .then at the same time but from what I can tell it's not good practice.

Related

Cannot access javascript variable outside the function

Why can't I access the variable field_count outside of loadData() function?
var field_count;
await loadData();
async function loadData() {
var response = await fetch('/get_data');
var data = await response.json();
field_count = data.field_count;
alert(field_count) // shows correct data
}
alert(field_count) //shows undefined
Here loadData() is an async function, but your alert(field_count) outside of any function is not async. You're doing two await() calls inside the function, which operate asynchronously as you've requested of the language. However, the alert() which is outside the function is operating synchronously. Under most circumstances, that top-level alert() will have run and tried to alert() an undefined value before the two await calls are completed.
Mixing async programming and synchronous programming in this way is fraught with traps and pitfalls. I would recommend until you are comfortable with the ideas of asynchronous code and how it differs from other code, set up the program first then stick to async code working with other async code. Once you are comfortable with both and understand the differences, you can consider using results from async code in sync code, but you'll need to learn about how to use promises or some other synchronization method.
Consider the output of this code.:
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 600);
});
}
var result;
async function asyncCall() {
console.log('calling');
result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall().then(() => {
console.log(result)
});
console.log(result);
That is going to quickly log "calling", then undefined, then wait 600 milliseconds and then log "resolved" and another "resolved" quickly.
This part uses promises to coordinate the async function with the parent program.:
asyncCall().then(() => {
console.log(result)
});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise explain all this fairly well.

How to call async/await function asynchronously in other functions?

I create common function that will be called several different times and that function is async/await type.
const storeData = async () => {
await User.create({name: "Test 123"})
}
Now if I want to call function storeData in many different functions asynchronously, do I call it with await in a front of it (option 1 bellow) or since it has async await inside of it, will be run as async function and there is no need for await in front (option 2 bellow)?
(Note: I could do workaround and make storeData to return a new Promise and then do the things inside the promise and be sure that await will really matters.)
Option 1.
async dummy1() {
await storeData();
...rest of thte code
}
Option 2.
async dummy2() {
storeData();
...rest of the code
}
In javascript, all asynchronous functions are identical to a regular function that returns a promise. The async is just syntactic sugar. So, if you use await before the function call, the function call will block execution, and if you don't use await then it'll run asynchronously, like you desire.
Read more here.

Do intermediate async functions not have to always be wrapped with `async` keyword in Javascript?

In the code example below function a returns a promise. Using await after return is useless but I thought (and according to the examples) the function returning the promise should still be an async function. However, even if I don't add async keyword to a it still works if it's awaited in function b. If I don't await a() inside b then bRes is a promise object and not 5. So this means that I can have an infinite number of functions like a which return promise and as long as the first function that calls this infinite chain awaits the result, then I don't need to wrap the intermediate functions with async?
const getPromise = () => new Promise((resolve, reject) => {
setTimeout(() => {
console.log('promise finished')
resolve(5)
}, 2000)
})
const a = () => {
console.log('from a')
return getPromise()
}
const b = async () => {
const bRes = await a()
console.log('bRes', bRes)
}
b()
You can only use await inside a function that is async
A function that is async will return a promise
Other means (such as new Promise) can be used to create a promise
You can only (usefully) await a promise
Since a() returns a promise, and b is async, you can await the return value of a() inside b.
No function need to use the async keyword unless the await keyword is used within it.
The await keyword will not work if used outside of functions marked with async. And that's the only technical use of the async keyword (if you want to use it for documentation purposes it's fine but it does nothing otherwise).
All other functions be they synchronous, promise generators, event handlers, observer handlers or just plain old callbacks don't need to be marked with async (unless you use await within them).

Is it possible to return a value from a callback inside an async function without using Promise?

Very straightforward question, I know when I write an async function like this:
const res = (async () => 'hello')();
console.log(await res);
It should log: 'hello'
But, lets say I want to timeout the result inside my async function, I would have to create a new Promise so I can wrap the timeout callback in it, like this:
const res = (async () =>
new Promise(resolve =>
setTimeout(
() => resolve('hello'), 1000
)
)
)();
console.log(await res);
Well, if async already returns a promise, why should I need to create a new Promise inside a function that is already a promise, to do something as simple as this?
Am I missing something or it is indeed designed to be this way?
Wouldn't it be better if I could just do something like this in a native way? Is it even possible?
For example:
const res = (async () =>
setTimeout(
() => resolve('hello'), 1000
)
)();
console.log(await res);
Generally speaking new Promise is meant for legacy callbacks,. And ideally you want to prevent using them as much as possible.
So in your example your using a setTimeout, and then resolving the string hello. Instead of doing this, it would make more sense to create a delay function, that you could use again then just return "hello"
eg.
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function test() {
const res = (async () => {
await delay(1000);
return "hello";
})();
console.log(await res);
}
test();
Ultimately you need to convert a 'callback style' function into a promise, so you can't really get around making that promise. If you think this is a bit ugly, I would suggest using or building a utility function that does this for you.
Aside: unless you use await in a function, there's not really a good reason to mark it as async. This is better:
const res = new Promise(resolve =>
setTimeout(
() => resolve('hello'),
1000
)
);
console.log(await res);
I think a good way to think about async/await is that it makes certain promise-patterns easier to write, but not everything you can do with a plain promise can also be done with async/await. async/await makes a common pattern (MUCH) more legible.
Well, if async already returns a promise, why should I need to create a new Promise inside a function that is already a promise, to do something as simple as this?
An async function has three features:
It creates a promise
The promise resolves with the return value
You can use await inside it
This makes it an excellent tool to manage other functions which return promises, as it lets you use await and write code that doesn't use lots and lots of callbacks.
It doesn't make it a universal tool for replacing all other uses of Promise.
You still need one for this.
For example:
const res = (async () =>
setTimeout(
() => resolve('hello'), 1000
)
)();
console.log(await res);
If this worked, then the resolve function would be springing out of nowhere, and the return value wouldn't be the value the function resolved as.
It would lose one of the benefits of async functions.
JavaScript is a big toolbox. Different tools are suited to different jobs.

Is there difference between return with await or without

I'm just thinking about we need to use the await operator, and what is the difference between the following two case.
one
public async updateOne(Model, doc, errorMsg?){
return await Model.findOneAndUpdate({'_id': doc._id}, {'$set': doc}, {upsert:true, new: true}).lean().exec();
}
two
public updateOne(Model, doc, errorMsg?){
return Model.findOneAndUpdate({'_id': doc._id}, {'$set': doc}, {upsert:true, new: true}).lean().exec();
}
I think there is no difference in the result, but I think it is completely unnecessary to use the async await, because a promise will be returned, and we only need to use the await operator when we call the updateOne function inside an async function.
As Oyverus answered, there's no difference in the result but using async functions will create another Promise, I've added some rough examples to each case.
Using async updateOne(){ return await Model.findOneAndUpdate(...) } results in Promise code something like:
return new Promise((resolve, reject) => {
Model.findOneAndUpdate(...).then(resolve, reject)
})
Then async updateOne(){ return Model.findOneAndUpdate(...) } is:
return new Promise(resolve => resolve(Model.findOneAndUpdate(...))
A plain updateOne(){ return Model.findOneAndUpdate(...) } is:
return Model.findOneAndUpdate(...)
I tend to use the plain return when possible, but leave an /*async*/ in the code for documentation purposes.
/*async*/ write(){
return this.db.write()
}
In this use case, there isn't a difference in the eventual result, but there is a difference in how it works.
Returning an awaited promise in an async function will return another promise that gets resolved with the value of the awaited promise, which is basically two promises, which in this use case is redundant, since you're not doing any extra processing on the promise.
Returning a promise in a regular function will just return that promise as is, and won't wrap it around another promise, so you're completely right that it is unnecessary to use async await in this way.
Is there difference between return with await or without? ... I think there is no difference in the result
Yup, you got it right. In your example there is no difference.
From MDN:
When an async function is called, it returns a Promise. When the async function returns a value, the Promise will be resolved with the returned value. When the async function throws an exception or some value, the Promise will be rejected with the thrown value.
An async function can contain an await expression, that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.
we only need to use the await operator when we call the updateOne function inside an async function.
Not exactly, the async operator just enables the use of await within the corresponding function and all the await operator does within that async function is unwrap a promise to the value it would return within the .then(value => /* do stuff with value */) callback. The purpose is so the code resembles a more familiar synchronous control flow.
The result of any invocation of a async function (i.e. the return type of it) will be a Promise of whatever you returned but note you can still use unwrapped promises (i.e. without await) within async functions, the values will just be wrapped in promises.
Let me know if you still need help understanding. I'll revise this post.
function simplePromise() { return Promise.resolve('resolved value'); }
async function asyncAwaitTest() {
const simplePromiseValue = await simplePromise();
console.log(simplePromiseValue); // resolved value
// if you don't use the `await` keyword, then the promise will still be a promise
simplePromise().then(value => console.log(value));
}
asyncAwaitTest();
The only diffrent is memory usage, which return await use more since an intermediate Promise object might be created.
The other good thing about Async/Await is that it allows us to catch any unexpected errors in a good old try/catch block. We just need to wrap our await calls like this:
async function doSomethingAsync(){
try {
// This async call may fail.
let result = await someAsyncCall();
}
catch(error) {
// If it does we will catch the error here.
}
}
The catch clause will handle errors provoked by the awaited asynchronous calls or any other failing code we may have written inside the try block.
You are correct that you don't need to use an async function when the only return value is the result of applying an await operator. Returning the promise operand of the await from a synchronous function that does not use await elsewhere is equivalent (as you coded in example "two").
The logic chain of
we only need to use the await operator when we call the updateOne function inside an async function
however is not exact. You can return the promise from within an async function without using await as in
three
public async updateOne(Model, doc, errorMsg?){
return Model.findOneAndUpdate({'_id': doc._id}, {'$set': doc}, {upsert:true, new: true}).lean().exec();
}
where the promise returned by Model will be used to resolve the promise returned by async.

Categories

Resources