How to combine async/await with Promises? - javascript

In the below code have I createPost() inside an async function, but I don't want to use await on it, so it blocks execution of the rest of the function. That is why I used then.
The outer async function have lots of other functions that use await, so that can't be changed.
Question
Since createPost() is a async/await function (see below). How can it resolve/reject to then/catch in the outer function?
module.exports = async (p) => {
// lots of code here
const t = await function1();
// lots of code here
createPost(p).then(message => {
// lots of code here
console.log("ok " + message);
}).catch(message => {
console.log("failed " + message);
});
};
createPost()
module.exports = async (p) => {
// lots of code here
try {
const r = await getStat();
} catch (error) {
console.log(error);
};
};

async / await is a more modern equivilant to .then / .catch.
In this case you have mixed the syntaxes of both.
You don't need try / catch blocks when using .then,
just like you don't need to declare a function as async when using the try / catch syntax.
Other than that there's no reason they can't work together in seperate functions.
module.exports = (p) => {
createPost(p).then(message => {
console.log("ok " + message);
}).catch(message => {
console.log("failed " + message);
});
};
createPost():
module.exports = async (p) => {
try {
const r = await getStat();
} catch (error) {
console.log(error);
};
};

An async decleration on a function is redundant and wrong if you're not using the await keyword inside.
await/async are often referred to as syntactic sugar, and let us wait for something (e.g. an API call), giving us the illusion that it is synchronous in an actual asynchronous code, which is a great benefit.
The things you want to acheive with async/await is is possible with promises but the advantages of async/await. let's an example with this code:
const makeRequest = () => //promise way
getJSON()
.then(data => {
return data
})
makeRequest();
const makeRequest = async () => { //async await way
const data = await getJSON();
return data;
}
makeRequest()
Why is async/await prefered over promise?
Concise and clean - We didn’t have to write .then and create an anonymous function to handle the response, or give a name data to a variable that we don’t need to use. We also avoided nesting our code. async/await is a lot cleaner.
Error handling - Async/await makes it finally possible to handle both synchronous and asynchronous errors with the same try/catch format.
Debugging - A really good advantage when using async/await is that it’s much easier to debug then promises for 2 reasons: 1) you can’t set breakpoints in arrow functions that return expressions (no body). 2) if you set a breakpoint inside a .then block and use debug shortcuts like step-over, the debugger will not move to the the following .then because it only “steps” through synchronous code.
Error stacks - The error stack returned from promises chain gives us no idea of where the error occured and can be misleading. async/await gives us the error stack from async/await points to the function that contains the error which is a really big advantage.

Related

How to avoid indented nested promises?

I heard that promises are supposed to be linear in code in opposed to callbacks ("callback hell").
Though I still have a scenario similar to callback hell and hoping promises can make their promise and have a linear syntax equivalent to this problem code.
Given promises p(), q(),w() consider this code:
p().then(() => {
q().then(() => {
w().then(() => {
// do something
})
})
})
Can we make an equivalent code which is not indented for every nested promise?
You should not nest the .then() handlers but let each .then() create and return a new Promise. This is how it was designed to work, otherwise you are still in the callback hell, now the version with promises. No big difference.
The code should be like this:
p()
.then(() => {
return q();
})
.then(() => {
return w();
})
.then(() => {
// do something
});
If all that the .then() handlers do is to call the next function you can write it in a simpler form (read about arrow functions):
p()
.then(() => q())
.then(() => w())
.then(() => {
// do something
});
Even more, if q and w are called without arguments, the code could be as simple as:
p()
.then(q)
.then(w)
.then(() => {
// do something
});
Or you can go the extra mile and instead of using .then() and .catch() you use await. The code becomes even more clear and easy to read:
try {
await p();
await q();
await w();
// do something
} catch (err) {
// write here the code you would write in the handler you pass to `.catch()
// in the approach that uses Promises
}
Remarks
If the code above, using await, is used in a function then that function must be an async function (just put async in front of its definition).
The code that uses await may or may not be used outside of a function (i.e. at module's top level) depending on the runtime you use to run it (browser, Node.js etc).
As another user mentioned, you could use async/await but another option is just to slightly restructure what you have. Here are some examples of what could work – depending on where and when you need certain pieces of data:
p()
.then(q)
.then(w)
// OR
p()
.then(() => q())
.then(() => w())
Obviously this gets a little more complicated if w() needs data from both p() and q() but that's the gist of it.
You could try using async/await, which leaves a more cleaner code. It would be like this:
(async () => {
try {
await p();
await q();
await w();
} catch (e) {
// handle error
}
})()
If there is no dependency between each promise you can use await Promise.all in order to do "all or nothing". In any other case, you can store the returned value and pass it to the next function in order to be used if needed.

Escape multiple nested functions in NodeJS

I have code in Javascript that looks like this:
function someFunction() {
// Code
somePromise().catch(err => {
console.log(err);
});
// Mode Code
}
I would like to escape both somePromise().catch and someFunction() in the event that somePromise() is rejected. I tried using return but that only allows me to escape somePromise().catch. Is there any function that would allow me to break out of nested loops?
You can do that by using async/await:
function async someFunction() {
// Code
try {
await somePromise();
} catch (err) {
console.log(err);
return; // aborts further execution
}
// More Code
}
See async function for details.
Async/await solves the problem but it's important to understand why it solves the problem.
Promises are a mechanism for storing continuations. Functions you pass to then and catch are stored within the promise and are executed when the promise is resolved.
To solve this without async/await, you would simply return the Promise and use then to execute any code that should execute when the Promise does not reject:
function someFunction() {
// Code
return somePromise()
.then(result => {
// More Code
})
.catch(err => {
console.log(err);
});
}
This is essentially what async/await de-sugars to. Async/await is syntactic sugar around a state machine that wires up these continuations for you.

Continue execution with async/await

Most of the articles mention that await is a replacement for then. However, I can't find a way to do the approach below by using await since it will defer execution until run query finishes. Just curious, is there a way?
this.database
.run(query, bindings)
.then(result => this.ws.send(result))
.catch(err => this.ws.error(err));
return reply.code(202).send();
The fact that you can't directly use async/await here should tip you off that what you have here isn't such a good idea. It's fire-and-forget code, which is rarely a good practice.
However, if that's actually what you want to do, one option available is to put the async/await in a separate method.
Separate method:
async runQuery(query, bindings) {
try {
const result = await this.database.run(query, bindings);
await this.ws.send(result);
} catch(err) {
await this.ws.error(err);
}
}
Main code:
this.runQuery(query, bindings);
return reply.code(202).send();

Difference of using async / await vs promises?

I am looking for a answer on what to use in my nodeJS app.
I have code which handles my generic dB access to mssql. This code is written using an async functions and then I used a promise to call that function and all works fine.
As my app is getting bigger and code larger I am planning to move some of the logic into functions and then call them.
So my question is: is there a drawback to using a mix of async/await and promises or does it really not matter?
Async / await makes it easier to write more readable code as I have to read and write to multiple db’s before I return something and I need results of some of these.
So the question is what is the better approach?
Async / await on dB layer that’s set and can’t change
The logic layer async / await which would allow me a async / and await on the function call or if I go with promise for logic then I am stuck with promise on function call.
So I hope someone can give me more insight if one has more advantages than the other, besides being able to write cleaner code.
async/await and promises are closely related. async functions return promises, and await is syntactic sugar for waiting for a promise to be resolved.
The only drawback from having a mix of promises and async functions might be readability and maintainability of the code, but you can certainly use the return value of async functions as promises as well as await for regular functions that return a promise.
Whether you choose one vs the other mostly depends on availability (does your node.js / browser support async?) and on your aesthetic preference, but a good rule of thumb (based on my own preference at the time of writing) could be:
If you need to run asynchronous code in series: consider using async/await:
return asyncFunction()
.then(result => f1(result))
.then(result2 => f2(result2));
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result2);
If you need nested promises: use async/await:
return asyncFunction()
.then(result => {
return f1(result)
.then(result2 => f2(result, result2);
})
vs
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result, result2);
If you need to run it in parallel: use promises.
return Promise.all(arrayOfIDs.map(id => asyncFn(id)))
It has been suggested you can use await within an expression to await multiple tasks like so:
*note, this still awaits in sequence from left to right, which is OK if you don't expect errors. Otherwise the behaviour is different due to fail fast behaviour of Promise.all()
const [r1, r2, r3] = [await task1, await task2, await task3];
(async function() {
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Create Promises');
const task1 = t1(100);
const task2 = t1(200);
const task3 = t1(10);
console.log('Await for each task');
const [r1, r2, r3] = [await task1, await task2, await task3];
console.log('Done');
}())
But as with Promise.all, the parallel promises need to be properly handled in case of an error. You can read more about that here.
Be careful not to confuse the previous code with the following:
let [r1, r2] = [await t1(100), await t2(200)];
function t1(t) {
console.time(`task ${t}`);
console.log(`start task ${t}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.timeEnd(`task ${t}`);
resolve();
}, t);
})
}
console.log('Promise');
Promise.all([t1(100), t1(200), t1(10)]).then(async() => {
console.log('Await');
let [r1, r2, r3] = [await t1(100), await t1(200), await t1(10)]
});
Using these two methods is not equivalent. Read more about the difference.
In the end, Promise.all is a cleaner approach that scales better to an arbitrary number of tasks.
Actually it depends on your node version, But if you can use async/await then your code will be more readable and easier to maintain.
When you define a function as 'async' then it returns a native Promise, and when you call it using await it executes Promise.then.
Note:
Put your await calls inside a try/catch, because if the Promise fails it issues 'catch' which you can handle inside the catch block.
try{
let res1 = await your-async-function(parameters);
let res2 = await your-promise-function(parameters);
await your-async-or-promise-function(parameters);
}
catch(ex){
// your error handler goes here
// error is caused by any of your called functions which fails its promise
// this methods breaks your call chain
}
also you can handle your 'catch' like this:
let result = await your-asyncFunction(parameters).catch((error)=>{//your error handler goes here});
this method mentioned does not produce an exception so the execution goes on.
I do not think there is any performance difference between async/await other than the native Promise module implementation.
I would suggest to use bluebird module instead of native promise built into node.
At this point the only reason to use Promises is to call multiple asynchronous jobs using Promise.all() Otherwise you’re usually better with async/await or Observables.
Its depending upon what approach you are good with, both promise and async/await are good, but if you want to write asynchronous code, using synchronous code structure you should use async/await approach.Like following example, a function return user with both Promise or async/await style.
if we use Promise:
function getFirstUser() {
return getUsers().then(function(users) {
return users[0].name;
}).catch(function(err) {
return {
name: 'default user'
};
});
}
if we use aysnc/await
async function getFirstUser() {
try {
let users = await getUsers();
return users[0].name;
} catch (err) {
return {
name: 'default user'
};
}
}
Here in promise approach we need a thenable structure to follow and in async/await approach we use 'await' to hold execution of asynchronous function.
you can checkout this link for more clarity Visit https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
Yesterday I made a tentative decision to switch from using Promises to using Async/Await, independent of nodejs, based on the difficulty in accessing previous values in the Promise chain. I did come up with a compact solution using 'bind' to save values inside the 'then' functions, but Async seemed much nicer (and it was) in allowing direct access to local variables and arguments. And the more obvious advantage of Async/Await is, of course, the elimination of the distracting explicit 'then' functions in favor of a linear notation that looks much like ordinary function calls.
However, my reading today uncovered problems with Async/Await, which derail my decision. I think I'll stick with Promises (possibly using a macro preprocessor to make the 'then' functions look simpler) until Async/Await gets fixed, a few years from now.
Here are the problems I found. I'd love to find out that I am wrong, that these have easy solutions.
Requires an outer try/catch or a final Promise.catch(), otherwise errors and exceptions are lost.
A final await requires either a Promise.then() or an extra outer async function.
Iteration can only be properly done with for/of, not with other iterators.
Await can only wait for only one Promise at a time, not parallel Promises like Promise chains with Promise.all.
Await doesn't support Promise.race(), should it be needed.

node 7.6 async await issues with returning data

I am working on a simple TCP client for a server and am using the latest node 7.6 because of the async/await functions. I'm new to node and asynchronous coding, so I apologize if this is stupidly easy.
I want to run a function that calls the callServer() function with specific parameters, wait until it finishes getting the data, and return the data as a variable.
Here is my code:
'use strict'
const net = require('net')
var formattedJson = funcRequestToJson("Server.GetStatus", false)
doThings()
async function doThings() {
var info = await callServer()
}
async function callServer() {
var client = new net.Socket()
client.connect(1705, '192.168.28.16', () => {
console.log('connected to server')
client.write(formattedJson)
})
client.on('data', (data) => {
client.destroy()
//return await data
console.log(data.toString())
})
client.on('close', () => {
})
}
// method and paramBool are always required
// macAddress, paramKey, paramValue are required for if paramBool is true
function funcRequestToJson(method, paramBool, macAddress, paramKey, paramValue) {
var objectRequest = {}
objectRequest[ "jsonrpc" ] = "2.0"
objectRequest[ "method" ] = method
objectRequest[ "id" ] = 0
if (paramBool == true) {
objectRequest[ "params" ] = {
"client": macAddress,
[paramKey]: paramValue
}
}
var json = (JSON.stringify(objectRequest) + '\r\n')
return json
}
So I didn't declare objectRequest() as async because it's not waiting on the server, but I think callServer() should be async, right? I know this can be done with promises, but I wanted to use async/await and this seems to be right.
Now, I want to return the data that comes from inside callServer() and client.on('data', (data) but I can't seem to figure out how to do it asynchronously. I would think there'd be a way to make an async function and call it with await like I tried (await return data) but it never works right.
I'm sorry if this is terribly convoluted, but I've been poring over async node tutorials for the past week and am still stuck.
Thanks!
Async/Await relies on code that uses promises for async operations. So you need to return a promise from any async operation in order to use it with async/await.
So, callServer() needs to return a promise that is resolved when the async operation inside it is done. In fact, you can only await an async operation in a function if that function returns a promise. await saves you from having to write .then() handlers on promises, but async/await does not magically know when async operations are done. You still have to wrap them in promises.
Here's an example of how you could make callServer() return a promise:
async function callServer(formattedJson) {
return new Promise((resolve, reject) => {
let client = new net.Socket()
client.connect(1705, '192.168.28.16', () => {
console.log('connected to server')
client.write(formattedJson)
})
client.on('data', (data) => {
resolve(data);
client.destroy()
})
client.on('close', () => {
})
client.on('error', reject);
});
}
Sample Usage:
try {
var info = await callServer(funcRequestToJson("Server.GetStatus", false));
} catch(e) {
// error here
}
Just to show you what await is doing, in ES5 (without async/await), the sample usage would be this:
callServer(funcRequestToJson("Server.GetStatus", false)).then(info => {
// info is available here
}).catch(err => {
// error here
});
So, await is just letting you avoid writing the .then() handler. Internally in the execution of the code, there's just a promise that the interpreter sets up a .then() handler for so it will know when that promise is resolved. This is syntactical sugar, not really any magic with async operations. You still have to use promises for all your async operations. You can use await instead of .then() and your code will appear more sequential even though it's really the same under the covers.
People think that await allows one to write asynchronous code as if it was synchronous, but that isn't really the case, especially if you handle errors and understand concurrency issues. It will look more synchronous, but isn't actually any more synchronous than it was with .then() in ES5.
And, watch out for error handling. In people's quest to write synchronous looking code, people seem to completely forget to handle rejected promises in their async operations (which are handled with try/catch when using await). I'm personally not yet convinced that ES6 is a step forward when it comes to error handling as the early indications are that ES6 seems to encourage people to just forget about error handling or get lazy and not do it, whereas it's easier when using .then() to just know that there should be a .catch() somewhere for it to be solid code. Maybe that's just a learning process, but it seems to be an early issue when people use await.

Categories