While I thought I was using Async and Await keywords properly, it appears as though I am doing something wrong.
I am using PouchDB, which is a great Javascript database that syncs with CouchDB. PouchDB uses promises for many of its functions, and has native support for Async and Await. As an example, to retrieve the basic information about a database, you would use the following code:
db.info().then(function (info) {
console.log(info);
})
I understand this, and it works. But if I try and put this inside a function, and then call that function, things go haywire. And I'm sure it's me and not PouchDB that is the problem...
function getLocalDBInfo(db){
try {
db.info().then(function (info) {
return info;
});
} catch (error) {
console.log("can't get local DB info: ", error);
}
}
async function testing(db){
try {
var info=await getLocalDBInfo(db);
await console.log("DB info=", info);
await console.log("Doc count= ", info.doc_count);
}
catch(err){
console.log("error=",err);
}
//info contains...
//{"doc_count":0,"update_seq":0,"db_name":"kittens"}
}
testing(MY_db);
If I log info inside the getLocalDBInfo function, it eventually (ie. after the promise fulfills) logs info to the console. But, the logs inside the testing function return immediately with undefined. It makes sense to me that they are returning undefined because they are returning immediately, but I was trying to have them wait for info by using async and await. Any suggestions as to what I am doing wrong?
getLocalDBInfo() is not returning a promise, so you can't await for it.
with async/await you could:
async function getLocalDBInfo(db){
try{
return await db.info()
} catch (err){
console.log("can't get local DB info: ", error);
}
}
you can also use new promise
getLocalDBInfo generates a promise, attaches a callback to it, then returns undefined. It doesn't return the resolved promise and you can't await on an undefined (well, you can, but it won't do anything).
You neee to change getLocalDBInfo to actually return the promise.
Also, why do you have a then block with the signature info => info? All this will do is unwrap the async value and then wrap it again. You can omit the then callback entirely.
Similarly, are you sure you need to wrap the db.info call in a try/catch? I wonder if you might be intending to use a promise.catch here instead. The try/catch construct only grabs promise rejections when awaiting an expression.
You need to return the value from the outer function getLocalDBInfo
function getLocalDBInfo(db) {
return new Promise((resolve, reject) => {
db.info()
.then(info => resolve(info))
.catch(err => reject(err))
})
}
Related
I want to remove indentations in a javascript funtion that inside has a variable that recive the value of a promise. Inside of it has a try-catch with some code and inside the try section has a fetch with his own then and catch.
My question is, how can I simplify the code, even creating new functions if needed, to reduce the amount of indentations.
Thanks for advance.
Here an example code:
function getData(url) {
const myVariable = new Promise((resolve, reject) => {
try {
fetch(url)
.then((resp) => resp.json())
.then(json) => {
//some code here
});
// more code here
resolve();
})
.catch(() => { // this catch is of the fetch
// more code here
resolve();
});
} catch (error) {
// more code here
reject();
}
});
}
Y tried to transform the fetch using the ES6 async-await but I can not use an async funtion inside a promise
You don't need a new Promise. Once you have a promise -- like returned by fetch() -- you don't need another promise to tell you when the first one resolves. The same is true when you have a promise coming from then() calls: you don't need an extra promise for them. It is an antipattern to use the promise constructor callback just to create another promise (using some API).
Your example code has syntax issues (there are more closing braces than opening), so the .catch() method is not called on a promise. Your comment suggests you want to call it on the promise returned by fetch, but then it should be chained before the first then call. Each then() returns a new promise, and maybe you wanted to chain .catch() on the last .then(). In that case it will catch rejections of any of the previously chained promises, which means the outer try/catch block is not going to ever execute the catch block -- there is nothing remaining that can cause a run time error.
Another issue with the code (once its syntax errors are fixed) is that although myVariable will be assigned a promise:
That promise will resolve to undefined
The getData function will return a promise that will resolve to undefined
That is not very useful. You should resolve that promise with the data you got from the json() promise.
You can use async await like so:
async function getData(url) {
try {
const resp = await fetch(url);
} catch(err) {
console.log("fetch failed with following error", err);
throw err; // rethrow so caller's promise gets rejected
}
try {
const data = await resp.json();
} catch(err) {
console.log("json() failed with following error", err);
throw err; // rethrow so caller's promise gets rejected
}
return data;
}
As in this example the error handling is nothing more than just reporting on errors and then bubble the error upwards, it would make sense that the caller would take the responsibility to report on errors:
function getData(url) {
fetch(url).then(resp => resp.json());
}
I would like to run this code with babel:
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
inside an async function without await the first line. is this OK?
how else can I run something that I don't care?
Can I just fire the non-promisified function del('key',null) without a callback?
Yes, you can do that, and it will run the two asynchronous functions in parallel. You've just created a promise and thrown it away.
However, this means that when the promise is rejected you won't notice. You'll just get an unhandledRejection eventually which will crash your process if not handled.
Is this OK? How can I run something that I don't care?
Probably it's not OK. If you truly wouldn't care, you hadn't run it in the first place. So you should be clear and explicit what you care about (and what not):
do you want to wait? (for side effects)
do you need the result?
do you want to catch exceptions?
If you only want to wait and don't care for the result value, you can easily throw away the result:
void (await someAsyncFunction()); // or omit the void keyword,
// doesn't make a difference in an expression statement
If you don't care about exceptions, you can ignore them using
… someAsyncFunction().catch(function ignore() {}) …
You can throw that away, await it, do anything with it.
If you want the result, you have to await it. If you care about exceptions, but don't really want to wait, you may want to execute it in parallel with the following functions:
var [_, res] = await Promise.all([
someAsyncFunction(), // result is ignored, exceptions aren't
someOtherAsyncFunction()
]);
return res;
inside an async function without await the first line. is this OK?
Yes, there are cases where you'd want to do this which are perfectly reasonable. Especially where you don't care about the result - one example is an analytics tracking operation that should not interfere with business critical code.
how else can I run something that I don't care?
In many ways, however simply calling the promise function works. Your del without a callback would probably work in this case but some functions don't guard against not passing callbacks, so you can pass an empty function instead (.del('key', () => {})).
You do want to however make sure that you know about it failing, even if you don't want to disrupt the operation of code - so please consider adding a process.on("unhandledRejection', event handler to explicitly ignore these particular exceptions or suppress them via:
redisClient.delAsync('key').catch(()=>{});
Or preferably, something like:
redisClient.delAsync('key').catch(logErr);
From all the research I've made so far, I think it's fine to do it, as long as you guarantee that the function you are not awaiting for guarantees a way to handle its own errors in case that happens. For example, a try-catch wrapping the whole function body, like you see in the following snippet for the asyncFunction.
It doesn't matter if the function throws synchronously or asynchronously. It guarantees the your mainFunction will complete no matter what. That's the key point here.
If you don't guarantee that, you have to risks:
If it throws synchronously, your main function will not complete.
If it throws asynchronously, you'll get an unhandled excepction
// THIS IS SOME API CALL YOU DON'T WANT TO WAIT FOR
const mockAPI = () => {
console.log("From mockAPI");
return new Promise((resolve,reject) => {
setTimeout(() => reject("LATE THROW: API ERROR"), 500);
});
};
// THIS IS THE SOME ASYNC FUNCTION YOU CALL BUT NOT AWAIT FOR
const asyncFunction = async (syncThrow) => {
try {
console.log("Async function START");
if (syncThrow) throw new Error("EARLY THROW");
await mockAPI();
console.log("Async function DONE");
}
catch(err) {
console.log("From async function catch");
console.log(err.message || err);
return;
}
};
// THIS IS YOUR MAIN FUNCTION
const mainFunction = async (syncThrow) => {
try {
console.clear();
console.log("Main function START");
asyncFunction(syncThrow);
console.log("Main function DONE <<< THAT'S THE IMPORTANT PART");
}
catch(err) {
console.log("THIS WILL NEVER HAPPEN");
console.log(err);
}
};
<div>
<button onClick="mainFunction(true)">Sync throw</button>
<button onClick="mainFunction(false)">Async throw</button>
</div>
Not in Node.js.
Node does not wait for ever-pending Promises. If other tasks are already completed and there is nothing left in the event loop, the Node process will be terminated even though there exists pending promise.
For the following script, if someOtherAsyncFunction() get resolved in 5 seconds, but redisClientAsync.delAsync('key') takes 10 seconds to execute, the Node process will be terminated after 5 seconds in theory, before the first line is resolved.
async function doSomething() {
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
}
await doSomething();
I have the following code where I am calling an api
const fetchToken = async () => {
const response = await axios.post("http://localhost:3000/api/getRedisData",
{
key: process.env.AUTH_TOKEN_NAME!,
});
console.log(response); // this returns what I expect it to return
return response;
};
Then I am calling the function like this.
fetchToken();
Now, this function works just fine. But when I try to save the data of this response like the following.
token = fetchToken().then((r) => r);
It returns a promise and it never resolves. What is happening and how do I wait until this promise resolves. I just need to wait and get the data. Thanks in advance.
I updated this question.
Let's suppose I have the following object.
const authMachine = createMachine<toggleAuth>({
id: "auth",
initial: "unauthenticated", // I want to chage this value based on token
context: {
//
},
states: {
//
},
});
Now I want to update the initial property based on if I am getting a token or not. Right now I am doing something like this.
initial: token ? "authenticated" : "unauthenticated"
So what's wrong here?
If you are in an async function, you can just await it to get the data.
const token = await fetchToken();
console.log(token);
// do other stuff with token
If you aren't, then you need to do everything you want done with the token in your then method. This is because you are calling an async method and without the ability to await it. The execution will just continue. The then function is the callback that happens when your async method completes successfully.
fetchToken().then(token => {
console.log(token)
// do other stuff with token
});
All async functions return a promise. So your fetchToken() function will always return a promise. The resolved value of that promise will be whatever value you return from the fetchToken() function body.
So, the caller of fetchToken() has to use await or .then() to get that resolved value. There is no free lunch with async/await. It's still asynchronous. await gives you synchronous-like behavior inside the function, but not outside the function.
To explain a little further. As fetchToken() executes, as soon as it hits the first await, it immediately suspends further execution of the function body and then immediately returns an unresolved promise back to the caller. The caller then continues to execute and the caller has to use .then() or await to know when the body of fetchToken() is actually done and what its final returned value is.
Then, sometime later, the promises you used await on inside of fetchToken() will resolve or reject and when the JS interpreter is back to the event loop, then it will continue executing the rest of the body of fetchToken() after the await. When it finally gets to the end of the function body or encounters a return statement, then it resolves the promise that was previously returned and the caller that is using either await or .then() will get notified that it is done and will be given the final return value as the resolved value of that promise. The caller can then process that final value and do its thing.
So, you probably want to be using something like this to get the final value or the error:
fetchToken().then(token => {
console.log(token);
// use the token value here
}).catch(err => {
console.log(err);
});
// you cannot use the token value here
If the call to fetchToken() itself is inside an async function, then it can use await also:
try {
let token = await fetchToken();
console.log(token);
// use the token value here
} catch(err) {
console.log(err);
}
I would like to run this code with babel:
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
inside an async function without await the first line. is this OK?
how else can I run something that I don't care?
Can I just fire the non-promisified function del('key',null) without a callback?
Yes, you can do that, and it will run the two asynchronous functions in parallel. You've just created a promise and thrown it away.
However, this means that when the promise is rejected you won't notice. You'll just get an unhandledRejection eventually which will crash your process if not handled.
Is this OK? How can I run something that I don't care?
Probably it's not OK. If you truly wouldn't care, you hadn't run it in the first place. So you should be clear and explicit what you care about (and what not):
do you want to wait? (for side effects)
do you need the result?
do you want to catch exceptions?
If you only want to wait and don't care for the result value, you can easily throw away the result:
void (await someAsyncFunction()); // or omit the void keyword,
// doesn't make a difference in an expression statement
If you don't care about exceptions, you can ignore them using
… someAsyncFunction().catch(function ignore() {}) …
You can throw that away, await it, do anything with it.
If you want the result, you have to await it. If you care about exceptions, but don't really want to wait, you may want to execute it in parallel with the following functions:
var [_, res] = await Promise.all([
someAsyncFunction(), // result is ignored, exceptions aren't
someOtherAsyncFunction()
]);
return res;
inside an async function without await the first line. is this OK?
Yes, there are cases where you'd want to do this which are perfectly reasonable. Especially where you don't care about the result - one example is an analytics tracking operation that should not interfere with business critical code.
how else can I run something that I don't care?
In many ways, however simply calling the promise function works. Your del without a callback would probably work in this case but some functions don't guard against not passing callbacks, so you can pass an empty function instead (.del('key', () => {})).
You do want to however make sure that you know about it failing, even if you don't want to disrupt the operation of code - so please consider adding a process.on("unhandledRejection', event handler to explicitly ignore these particular exceptions or suppress them via:
redisClient.delAsync('key').catch(()=>{});
Or preferably, something like:
redisClient.delAsync('key').catch(logErr);
From all the research I've made so far, I think it's fine to do it, as long as you guarantee that the function you are not awaiting for guarantees a way to handle its own errors in case that happens. For example, a try-catch wrapping the whole function body, like you see in the following snippet for the asyncFunction.
It doesn't matter if the function throws synchronously or asynchronously. It guarantees the your mainFunction will complete no matter what. That's the key point here.
If you don't guarantee that, you have to risks:
If it throws synchronously, your main function will not complete.
If it throws asynchronously, you'll get an unhandled excepction
// THIS IS SOME API CALL YOU DON'T WANT TO WAIT FOR
const mockAPI = () => {
console.log("From mockAPI");
return new Promise((resolve,reject) => {
setTimeout(() => reject("LATE THROW: API ERROR"), 500);
});
};
// THIS IS THE SOME ASYNC FUNCTION YOU CALL BUT NOT AWAIT FOR
const asyncFunction = async (syncThrow) => {
try {
console.log("Async function START");
if (syncThrow) throw new Error("EARLY THROW");
await mockAPI();
console.log("Async function DONE");
}
catch(err) {
console.log("From async function catch");
console.log(err.message || err);
return;
}
};
// THIS IS YOUR MAIN FUNCTION
const mainFunction = async (syncThrow) => {
try {
console.clear();
console.log("Main function START");
asyncFunction(syncThrow);
console.log("Main function DONE <<< THAT'S THE IMPORTANT PART");
}
catch(err) {
console.log("THIS WILL NEVER HAPPEN");
console.log(err);
}
};
<div>
<button onClick="mainFunction(true)">Sync throw</button>
<button onClick="mainFunction(false)">Async throw</button>
</div>
Not in Node.js.
Node does not wait for ever-pending Promises. If other tasks are already completed and there is nothing left in the event loop, the Node process will be terminated even though there exists pending promise.
For the following script, if someOtherAsyncFunction() get resolved in 5 seconds, but redisClientAsync.delAsync('key') takes 10 seconds to execute, the Node process will be terminated after 5 seconds in theory, before the first line is resolved.
async function doSomething() {
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
}
await doSomething();
I have a simple code in JavaScript that execute a request in an API and return the response, simple. But in this case I will have thousands of requests. So, which one of the code options will perform better, and why. Also which one is recommended as good pratices these days?
First options is using the .then to resolve the promises and the seccond one is using async / await.
In my tests the two options had very similar results without significant differences, but I'm not sure in scale.
// Using then
doSomething(payload) {
const url = 'https://link-here/consultas';
return this.axios.get(url, {
params: {
token: payload.token,
chave: payload.chave,
},
}).then(resp => resp.data);
}
// Using Async / await
async doSomething(payload) {
const url = 'https://link-here/consultas';
const resp = await this.axios.get(url, {
params: {
token: payload.token,
chave: payload.chave,
},
});
return resp.data;
}
Any explanation will be of great value.
From a performance point of view, await is just an internal version of .then() (doing basically the same thing). The reason to choose one over the other doesn't really have to do with performance, but has to do with desired coding style or coding convenience. Certainly, the interpreter has a few more opportunities to optimize things internally with await, but its unlikely that should be how you decide which to use. If all else was equal, I would choose await for the reason cited above. But, I'd first choose which made the code simpler to write and understand and maintain and test.
Used properly, await can often save you a bunch of lines of code making your code simpler to read, test and maintain. That's why it was invented.
There's no meaningful difference between the two versions of your code. Both achieve the same result when the axios call is successful or has an error.
Where await could make more of a convenience difference is if you had multiple successive asynchronous calls that needed to be serialized. Then, rather than bracketing them each inside a .then() handler to chain them properly, you could just use await and have simpler looking code.
A common mistake with both await and .then() is to forget proper error handling. If your error handling desire in this function is to just return the rejected promise, then both of your versions do that identically. But, if you have multiple async calls in a row and you want to do anything more complex than just returning the first rejection, then the error handling techniques for await and .then()/.catch() are quite different and which seems simpler will depend upon the situation.
There should be some corrections in this thread. await and .then are going to give very different results, and should be used for different reasons.
await will WAIT for something, and then continue to the next line. It's also the simpler of the two because it behaves mechanically more like synchronous behavior. You do step #1, wait, and then continue.
console.log("Runs first.");
await SomeFunction();
console.log("Runs last.");
.then splits off from the original call and starts operating within its own scope, and will update at a time the original scope cannot predict. If we can put semantics aside for a moment, it's "more asynchronous," because it leaves the old scope and branches off into a new one.
console.log("Runs first.");
SomeFunction().then((value) => {console.log("Runs last (probably). Didn't use await on SomeFunction().")})
console.log("Runs second (probably).");
As more explanation to #user280209 answer let's consider the following function which returns promise and compare its execution with .then() and async await.
function call(timeout) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`This call took ${timeout} seconds`);
resolve(true);
}, timeout * 1000);
});
}
With .then()
(async () => {
call(5).then((r) => {
console.log(r);
});
await call(2); //This will print result first
await call(1);
})();
When running the above call the logs will be
This call took 2 seconds
This call took 1 seconds
This call took 5 seconds
true
As we can see .then() didn't pause the execution of its below line until it completes.
With async/wait
(async () => {
await call(5); //This will print result first
await call(2);
await call(1);
})();
When run the above function logs will be
This call took 5 seconds
This call took 2 seconds
This call took 1 seconds
So I think if your promise's result won't be used in the following lines, .then() may be better.
For those saying await blocks the code until the async call returns you are missing the point. "await" is syntactic sugar for a promise.then(). It is effectively wrapping the rest of your function in the then block of a promise it is creating for you. There is no real "blocking" or "waiting".
run();
async function run() {
console.log('running');
makePromises();
console.log('exiting right away!');
}
async function makePromises() {
console.log('make promise 1');
const myPromise = promiseMe(1)
.then(msg => {
console.log(`What i want to run after the promise is resolved ${msg}`)
})
console.log('make promise 2')
const msg = await promiseMe(2);
console.log(`What i want to run after the promise is resolved via await ${msg}`)
}
function promiseMe(num: number): Promise<string> {
return new Promise((resolve, reject) => {
console.log(`promise`)
resolve(`hello promise ${num}`);
})
}
The await line in makePromises does not block anything and the output is:
running
make promise 1
promise
make promise 2
promise
exiting right away!
What i want to run after the promise is resolved hello promise 1
What i want to run after the promise is resolved via await hello promise 2
Actually.
Await/Async can perform more efficiently as Promise.then() loses the scope in which it was called after execution, you are attaching a callback to the callback stack.
What it causes is: The system now has to store a reference to where the .then() was called. In case of error it has to correctly point to where the error happens, otherwise, without the scope (as the system resumed execution after called the Promise, waiting to comeback to the .then() later) it isn't able to point to where the error happened.
Async/Await you suspend the exection of the method where it is being called thus preserving reference.
If we just consider performance(time taken) then it actually depends on whether your operations are serial or parallel. If your tasks are serial then there will be no difference between await and .then. But if your tasks are parallel then .then will take less time. Consider the following example
let time = Date.now();
// first task takes 1.5 secs
async function firstTask () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
},1500)
})
}
// second task takes 2 secs
async function secondTask () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2);
},2000)
})
}
// using await
async function call(){
const d1 = await firstTask();
const d2 = await secondTask();
console.log(Date.now()-time, d1+d2)
}
call()
// using .then
async function call2(){
let d1=null,d2=null;
firstTask().then(data => {
d1=data;
if(d2){
console.log(Date.now()-time, d1+d2);
}
})
secondTask().then(data => {
d2=data;
if(d1){
console.log(Date.now()-time, d1+d2);
}
})
}
call2()
Here are the two tasks, first takes 1.5 secs and second takes 2 secs. Call function uses await where as call2 function uses .then . The output is as follows
From call2 2012 3
From call 3506 3
I hope it helps.
As far as I understand .then() and await are not the same thing. An async function won't proceed with the next command until the promise is resolved/rejected since it's basically an implementation of generators. On the contrast, in the case of .then(), the execution of the function will proceed with the next command and the resolve/reject callback will be executed "when there's time" aka when the current event loop (not entirely sure about that part) will be completed.
tldr; on a single promise await and .then() behave similarly but when one promise needs another one to be resolved first then the two of them behave entirely different
Many answer have been provided to this question already. However, to point out key information in the answers above and from my understanding, note below point:
only use await when not handling error return
if no crucial need for error handling use await instead
use .then .catch if returned error message or data is crucial for debugging / or proper error handling instead of try catch for await
Choose any prefer method from code sample below
const getData = (params = {name: 'john', email: 'ex#gmail.com'}) => {
return axios.post(url, params);
}
// anywhere you want to get the return data
// using await
const setData = async () => {
const data = await getData();
}
// to handle error with await
const setData = async () => {
try {
const data = await getData();
}
catch(err) {
console.log(err.message);
}
}
// using .then .catch
const setData = () => {
var data;
getData().then((res) => {
data = res.data; console.log(data)
}).catch((err) => {
console.log(err.message);
});
}