I'm doing some functional testing with mocha. I stored my functions name, parameters and sucess message in local JSON file. I am checking my database response with local JSON response.
I'm using .then and .catch everywhere. I am looking to clean up a code with async await. How I can use async await here?
it('Check Authentication', (done) => {
readFileData('checkAuth').then(({ params, message}) => {
login.checkAuth({ ...params })
.then((result) => {
assert(result.message === message);
done();
})
.catch((err) => done(err));
});
});
Something like this. Haven't tested it tho. Basically instead of .then() you just await the call. Note that there is async before (done) callback. .catch() can be caught with try/catch block.
it('Check Authentication', async (done) => {
let response = await readFileData('checkAuth');
try {
let message = await login.checkAuth({ ...response.params }); // or w/e the response is
// assert the message
} catch (e) {
// do something with the error
}
});
Changed callback function to async to use `await
Wrapped all await calls in try-catch block to handle errors
Used const for params, message and result variables but if you are going to reassign values later in the code you can use let instead.
done() will be async call. Add await in front of that if you need that too to be sync call
it('Check Authentication', async (done) => {
try {
const { params, message } = await readFileData('checkAuth');
const result = await login.checkAuth({ ...params });
assert(result.message === message);
done();
} catch (err) {
done(err);
}
});
Related
Excerpt of a lambda function using nodejs 12.
There is a promise (aws dynamo db document client query) nested inside a promise (node-fetch API request).
The first promise works fine. It executes the request, waits for the promise to resolve, and then enters the .then(...) to execute some code. Next, it executes the database query, but then it exits the whole function without waiting for the promise to resolve, even though there are still callbacks. It doesn't throw errors either. (I know the database query is being executed , as extra logging showed it's status to be <pending>)
When I try var dbscan = await db.scan(...) using await, I get the error await is only valid in async function. But the handler function is already async, and await is working for the fetch promise.
Q: how can I use await inside the .then(...) of the first promise?
Q: why is the process exiting without waiting for the promise to resolve?
exports.myhandler = async (event, context, callback) => {
var response = await fetch(url, {... my options ...})
.then(res => res.text())
.then(data => {
// do some stuff with the data ...
var dbscan = db.scan({...my params ...}).promise()
.then(res => {
// do some stuff with result ...
callback(null, <some message>);
}).catch(err => {
console.log(err);
callback(null, <some message>);
});
})
.catch(error => {
console.log('error', error);
callback(null, <some message>);
});
}
You have to add async to the beginning of the function in which you want to use await.
.then(async(data) => {
var dbscan = await ...
})
Since you're already using the async/await-syntax, you shouldn't have to resolve to using .then(..) chains.
You could flatten most of your code like this:
const response = await fetch(url, {... my options ...});
const data = await response.text();
// Do some stuff with the data...
const result = await db.scan({...my params ...});
// Do some stuff with the result...
On the way of learning the concepts of asynchronous JavaScript, I got struggled with the idea behind the situation when they can be chained. As an example consider the following situation: a webhook calls a cloud function and as a requirement there is set a time interval by which the cloud function should response to the webhook. In the cloud function is called an operation for fetching some data from a database, which can be short- or long-running task. For this reason we may want to return a promise to the webhook just to "register" a future activity and later provide results from it e.g.:
async function main () {
return new Promise ((resolve, reject) => {
try {
db.getSomeData().then(data=> {
resolve({ result: data});
});
} catch (err) {
reject({ error: err.message });
}
});
}
Another way is to use async/await instead of a promise for fetching the data, e.g.:
async function main () {
return new Promise (async (resolve, reject) => {
try {
const data = await db.getSomeData();
resolve({ result: data });
} catch (err) {
reject({ error: err.message });
}
});
}
(The code is a pseudo-code and therefore all checks on the returned types are not considered as important.)
Does the await block the code in the second example and prevent returning of the promise?
async functions always return a Promise. It is up to the function caller to determine how to handle it: either by chaining with then/catch or using await. In your example, there is no need to create and return a new Promise.
You could do something like this for example:
async function main () {
try {
const data = await db.getSomeData()
return {result: data}
} catch (err) {
return {error: err.message}
}
}
// On some other part of the code, you could handle this function
// in one of the following ways:
//
// 1.
// Chaining the Promise with `then/catch`.
main()
.then((result) => console.log(result)) // {result: data}
.catch((err) => console.log(err)) // {error: err.message}
// 2.
// Using await (provided we are working inside an asyn function)
try {
const result = await main()
console.log(result) // {result: data}
} catch (err) {
console.log(err) // {error: err.message}
}
Try to avoid combining both methods of handling asynchronous operations as a best practice.
I am kind of new in Javascript and I want to connect to DB and run a script. Then get the result of script and run functions in order.
If there is any error with one of the functions, it should stop and doesnt run other functions.
I tried the following:
const {
Client
} = require('pg')
const client = new Client({
'connection info'
})
client.connect()
.then(() => console.log('DB connected'))
.catch(err => console.error('connection error', err.stack))
let dbResult
const data = async() => {
try {
dbResult = await client.query('SCRIPT') // array of json
} catch (error) {
console.log(error);
}
}
const func1 = async() => {
try {
// do something with dbResult
console.log('func1 success msg')
} catch (error) {
console.log('error in func1')
}
}
const func2 = async() => {
try {
// do something with dbResult
console.log('func2 success msg')
} catch (error) {
console.log('error in func2')
}
}
const func3 = async() => {
dbResult.forEach(result => {
// do something
})
try {
// do something with dbResult
console.log('func3 success msg')
} catch (error) {
console.log('error in func3')
}
}
data()
func1()
func2()
func3()
All the functions you call are async, therefore return Promises and should be awaited. You can await all of them in a try/catch block, so if one fails, the others won't execute.
Don't use try/catch in each individual function, but rather here :
const data = async() => client.query('SCRIPT') // array of json
const func1 = async() => console.log('func1 success msg')
const func2 = async() => console.log('func2 success msg')
const func3 = async() => dbResult.forEach(result => console.log(result))
(async () => {
try{
await client.connect();
let dbResult = await data();
dbResult = await func1(dbResult);
await func2();
await func3(dbResult);
} catch(err) {
console.log(err);
}
})();
await Promise.all([data, func1, func2, func3]) would also fail if one of the Promises failed, but does not guarantee the execution order.
Below is if you must use try catch inside each of your function body. If not, then I'd stick with the answer from Jeremy above.
What you can do is instead of console logging your errors that you receive in try..catch block, you can throw new error, which will stop the execution of your code and console log the actual error.
(Well, not exactly console log, but rather console.error() it)
This will prevent the execution of other functions, unless you do something with your error (make some error handling where you can execute another code, depending on the error).
In general, the syntax for this as follows:
try {
await someStuff();
} catch (err) {
throw new Error(err)
}
Object err has some additional properties, such as name and message.
Here is more about Error object.
I am having a problem where an async function does not appear to be waiting. I am calling one async function from another, with the second returning a value after async operations have completed and then the first should be returning this as it has awaited it. But when logging accessToken in the first function it logs before awaiting the return from the second. Where am I going wrong? Thanks in advance.
export const confirmCode = async (verificationId, code) => {
try {
const credential = await firebase.auth.PhoneAuthProvider.credential(verificationId, code);
const accessToken = await authenticate(credential);
console.log(accessToken); // prints undefined as does not wait for above function call?
return accessToken;
} catch (error) {
console.log(error)
// this.showMessageErrorByCode(e.error.code);
}
}
const authenticate = async (credential) => {
try {
await firebase.auth().signInWithCredential(credential).then(result => {
const user = result.user;
user.getIdToken().then(accessToken => {
return accessToken;
});
})
} catch (error) {
console.log(error);
}
}
You should not mix async/await with the older version .then().
Just use it without then() like so:
export const confirmCode = async (verificationId, code) => {
try {
const credential = await firebase.auth.PhoneAuthProvider.credential(verificationId, code);
const accessToken = await authenticate(credential);
console.log(accessToken); // prints undefined as does not wait for above function call?
return accessToken;
} catch (error) {
console.log(error)
// this.showMessageErrorByCode(e.error.code);
}
}
const authenticate = async (credential) => {
try {
let result = await firebase.auth().signInWithCredential(credential); // <-- use await
const user = result.user;
accessToken = await user.getIdToken(); // <-- use await
return accessToken;
} catch (error) {
console.log(error);
}
}
For more detailed explanation, why your code does not work:
You are returning from within a .then() which is not possible
If you would want to use the old way of writing async functions, you would need to use:
return new Promise((resolve, reject) => { /* Code ... */ }); to wrap your function content
resolve(accessToken) instead of return
.then() and .catch() instead of await and try/catch
and some rejects where you can't resolve anything (so probably in the catch block)
But I would suggest you to use the async/await approach, as it is easier to read.
I have an array of Id' and i need to get the details for each of them.
i currently have this.
const redis = require('redis');
const redisClient = redis.createClient(process.env.REDIS_PORT, process.env.REDIS_HOST);
const arrayList = [
{ id: 3444 },
{ id: 3555 },
{ id: 543666 },
{ id: 12333 },
];
async function getDetails(element) {
await redisClient.hgetall(element.id, (err, user) => {
if (err) {
console.log('Something went wrong');
// Handle Error
return err;
}
console.log('Done for User');
return user;
});
}
arrayList.forEach((element) => {
console.log('element');
await getDetails(element).then((res) => {
// Do Something with response for each element
});
});
This is the response i get right now. its not async. What am i doing wrong please.
element
element
element
element
Done for User
Done for User
Done for User
Done for User
So how things go on in async/await is, you create an async function and inside that function you await for other operations to finish. You call that async function without await OR you wrap it(func call) inside another async function.
arrayList.forEach((element) => {
console.log('element');
let returnedPromise= getDetails(element);
console.log("Promise after getDetails function", returnedPromise);
});
This code change should resolve the error.
Array.forEach() does not wait for promises to execute before moving to the next item.
You could instead use a for-loop in an async function, like so:
async function main() {
for (const element of arrayList) {
const response = await getDetails(element);
// do something with reponse for each element
}
}
main()
.then(() => /* on success */)
.catch((err) => /* on error */);