I'm currently writing small NodeJS CLI tool for personal usage and I've decided to try ES7 async/await feature with Babel.
It's a network tool so I obviously have asynchronous network requests. I wrote a simple wrapper for request
package:
export default function(options) {
return new Promise(function(resolve, reject) {
request({...options,
followAllRedirects: true,
headers: {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0"
}
}, (error, response, body) => {
if(error) {
return reject(error);
}
resolve({response: response, body: body});
});
});
}
Now I can do something like
async function getGooglePage() {
try {
var r = await request({url: "http://google.com"});
console.log(r.body);
console.log("This will be printed in the end.")
} catch(e) {
console.log(e);
}
}
getGooglePage();
And now I have a question: I do requests in many places and I have to mark all these functions as async
, is it a good practice? I mean that almost every function in my code should be async
because I need to await
a result from other async
functions. That's why I think that I misunderstood async/await concept.
async/await is sometimes called "contagious" or "viral" (or so it has in the C# world), because in order for it to be effective, it needs to be supported all the way down the call chain. Forcing something asynchronous to act synchronous can lead to unintended results, so you should extend it from the original method all the way down to the top level consumer using it. In other words, if you create or use a type that uses it, that type should also implement it, and so on all the way up the chain. So yes, it's expected that you add async to every function that itself relies on it. Just note, however, you should not add preemptively add async to functions that don't actually implement or need it.
Just think: If you use async
(by await
ing something, I mean), you are async
. Avoid squashing an async
call into something synchronous.
I do requests in many places and I have to mark all these functions as async
Yes, if all your code is asynchronous, then you'd use async
functions everywhere.
Having all your code be asynchronous makes things complicated though. You have to worry about race conditions everywhere, make sure to handle reentrant functions correctly, and remember that during every await
basically anything can happen.
I mean that almost every function in my code should be async because I need to await a result from other async functions.
This might not be a best practise. You could try to break down your code into smaller units, most of which are usually not asynchronous. So instead of writing
async function getXandThenDoY(xargs) {
let res = await get(xargs);
…
return …;
}
you should consider making two functions
function doY(res) {
// synchronous
…
return …;
}
function getXandDoY(xargs) {
// asynchronous
return get(xargs).then(doY);
}
/* or, if you prefer:
async function getXandDoY(xargs) {
return doY(await get(xargs));
}
*/
I had the same question.
And found a great answer here → ‘Pitfall 3: your whole stack needs to be async’
No, async/await
is not contagious. (I believed the same thing for some time, too)
You can always treat the result of a sync function like a promise, and you are back to normal.
From developer.mozilla.org:
The async function declaration defines an asynchronous function…
Return value: A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.
Sample code:
const log = console.log; // just lazy shorthand
// just to delay, as seen in many places
function promiseTimeout(time, value) {
return new Promise(function(resolve, reject) {
setTimeout(function() { resolve(value); }, time);
});
};
// the thing you care about
async function foo() {
Promise.resolve('here')
.then((a) => {log('doing stuff '+a); return 'pear'})
.then(function(v) {
return promiseTimeout(1000,v)
});
};
// treat async-function like promise:
foo().then(function(){ log('folling up in main, ')});
// log('bad end');
gets you:
doing stuff here
following up in main
Enabling 'bad end' would show up too early. You can only await stuff it you use await. (And if you do, remember: It's just syntactic sugar, saving you of stuffing your follow-up code into .then()
clasuses... nice, but no more than that.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With