Trying to write a little chrome extension, which relies on the callback-heavy query functions of the chrome.*
interface, I quickly landed at promises and async/await, as I needed to guarantee the order of certain operations, while trying to avoid callback hell.
However, once I introduced async/await into some functions, every function that used them also had to be turned into an async function
in order to be able to await
the return value. Eventually even some global constants became promises, e.g.
const DEBUG = new Promise(function(resolve){
chrome.management.getSelf(resolve);
}).then(function(self){
return self.installType == 'development';
});
However, now I need to write await
everywhere and introducing weird bugs like if(DEBUG){...}
always being executed becomes way too easy.
While it seems possible to identify the errors using ESLINT, writing await
everywhere seems unnecessarily cumbersome and thus I was wondering if Javascript has some better construct that I am missing?
(Subjectively my current use of await/async seems backwards; Promises are kept as-is unless explicitly awaited, but it seems more desirable to me to have promises awaited by default in async functions and kept as bare promises only when explicitly requested.)
Use Promise. all to Stop Async/Await from Blocking Execution in JS.
The await expression causes async function execution to pause until a promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment.
If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call. By default, this message is a warning.
In this way, an async function without an await expression will run synchronously. If there is an await expression inside the function body, however, the async function will always complete asynchronously. Code after each await expression can be thought of as existing in a .then callback.
For the lack of a type system that would allow to catch such mistakes easily (did you consider Typescript or Flow?), you can use Systems Hungarian Notation for your variable names. Choose a prefix of suffix like P
, Promise
or $
and add it to all your promise variables, similar to how asynchronous functions are often named with an Async
suffix. Then only do things like
const debug = await debugPromise
where you can quickly see that if (debug)
is fine but if (debugPromise)
is not.
Once I introduced async/await into some functions, every function that used them also had to be turned into an async function in order to be able to await the return value. Eventually even some global constants became promises
I would not do that. Try to make as few functions asynchronous as possible. If they are not doing intrinsically asynchronous things themselves but only rely on the results of some promises, declare those results as parameters of the function. A simple example:
// Bad
async function fetchAndParse(options) {
const response = await fetch(options);
// do something
return result;
}
// usage:
await fetchAndParse(options)
// Good:
function parse(response) {
// do something
return result;
}
// usage:
await fetch(options).then(parse) // or
parse(await fetch(options))
The same pattern can be applied for globals - either make them explicit parameters of every function, or make them parameters of a module function that contains all others as closures. Then await
the global promises only once in the module, before declaring or executing anything else, and use the plain result value afterwards.
// Bad:
async function log(line) {
if (await debugPromise)
console.log(line);
}
async function parse(response) {
await log("parsing")
// do something
return result;
}
… await parse(…) …
// Good:
(async function mymodule() {
const debug = await debugPromise;
function log(line) {
if (debug)
console.log(line);
}
function parse(response) {
log("parsing")
// do something
return result;
}
… parse(…) …
}());
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