Top level await() without async() function in NodeJs

24 / Jan / 2023 by shivang.chaturvedi 0 comments

Here’s how async-await function typically works:

function myDummyBackendCall() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "Shivang",
id: "asmdhajkdhajdsh8qweuqoweuiqepoi-0q-0eueiuaisjdaKcjaisku",
});
});
});
}

// Used an async wrapper function to make an await call
(async () => {
let data = await myDummyBackendCall();
console.log(data);
})();

If you are a JS developer, you would know that without async function, await call will run into an error. And rightly so. The error will look something like this:

Let’s now talk about a different scenario

Here’s another example of my index.js file inside my NodeJs project wherein I haven’t enclosed my await call inside an asyncfunction (Node version that I am using is 19.3.0):

function myDummyBackendCall() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "Shivang",
id: "asmdhajkdhajdsh8qweuqoweuiqepoi-0q-0eueiuaisjdaKcjaisku",
});
});
});
}

//Note that there is no async wrapper function

let data = await myDummyBackendCall();
console.log(data);
// Output of node index.js
{
name: 'Shivang',
id: 'asmdhajkdhajdsh8qweuqoweuiqepoi-0q-0eueiuaisjdaKcjaisku'
}

You must be wondering how this is done and trust me, it’s fairly simple. All you have to do is to add a simple configuration, “type” with “module” as its value in the package.json file. Here’s an example:

{
"name": "src",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type":"module", // I'm here!
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"author": "",
"license": "ISC"
}

Behind the scenes

Within a package.json , “type” value of “module” tells NodeJs to interpret the files with .js extension as using ES module syntax, e.g.: import statement or import() expressions.

“type” defines how NodeJs runtime should resolve specifiers or load modules.

There are two possible values for “type” config:

  1. module
  2. commonjs (default)

There are ways to mix things up without adding type to the package.json file. Since we know that commonjs is the default value applied to your NodeJs project, every file with .js extension will be treated as CommonJS. But if you still want to load a file(s) as an ES Module, simply give the file .mjs extension.

Here’s the sample code (without type configuration):

{
"name": "src",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"author": "",
"license": "ISC"
}

Here’s the screenshot of the .mjs file:

Here’s the code inside index.mjs (exactly same code as above):

function myDummyBackendCall() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "Shivang",
id: "asmdhajkdhajdsh8qweuqoweuiqepoi-0q-0eueiuaisjdaKcjaisku",
});
});
});
}

console.log(await myDummyBackendCall());

Here’s the result:

Here are some points straight from the official NodeJs documentation

  1. Files ending with .mjs are always loaded as ES modules regardless of the nearest parent package.json.
  2. Files ending with .cjs are always loaded as CommonJS regardless of the nearest parent package.json.

But before you get overly optimistic…

This only works when await call is made at the top level of modules. Here’s an illustration:

ECMAScript module loader is asynchronous. It means that top-level await enables the module to act like a BIG async function when NodeJs loads it as ES Module. Hence, the top-level await doesn’t need an explicit async function wrapper. It also means that an await without async is a myth!

Disclaimer

This is purely a NodeJs feature. There is no concept of .mjs and .cjs in vanilla JavaScript.

***

Note of thanks ❤️

Thank you for stopping by. Hope, you find this article helpful. Please follow me on medium and help me reach 1k followers ??. That will truly encourage me to put out more content.

P.S.: If you feel something can be improved or lacks proper explanation, drop me a note in the comment box or mail me at shiva.chaturvedi91@gmail.com. After all, you can teach me a thing or two as well.

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *