27

I am trying to do something like this on global scope in nodejs REPL. As per my understanding both the following statements are valid. see docs

let x = await Promise.resolve(2);
let y = await 2;

However, both these statements are throwing an error.

Can somebody explain why? my node version is v8.9.4

3
  • 3
    Why? Because that's how async/await was designed. If you want to go into why it's designed that way, it is complicated, but it has to do with the single-threaded event driven nature of Javascript and how much change they could absorb in one major revision of the engine. And, with modules assuming to be loading synchronously, top level await causes all sorts of problems with that assumption. Put your own async wrapper around things you want to use await with. Commented Jul 25, 2018 at 18:14
  • 4
    You don't or you wait for top-level async to cause a whole slew of issues. Commented Jul 25, 2018 at 18:15
  • You could write your own REPL that wraps all code entered in an AIiFE. Commented Jul 25, 2018 at 18:34

6 Answers 6

36

Update

When using Node, the file currently must have an .mjs extension to work.

Top level awaits can be used in browser modules. When used the script tag must include the type attribute which must be set to module:

<script src="/script.js" type="module"></script>
const start = Date.now()

console.log('Pre call.')
await delayedCall()
console.log('Duration:', Date.now() - start)

function delayedCall() {
  return new Promise(resolve => setTimeout(() => resolve(), 2000))
}

Old Answer

await can only be used within a function that is labeled async, so there are two ways you can approach this.

Note: There is a proposal in place that may eventually allow the usage of Top level await calls.

The first way is to create a self invoked function like this:

(async function() {
  let x = await Promise.resolve(2)
  let y = await 2
  
  console.log(x, y)
})()

Or the second way is to use .then()

Promise.resolve(2).then(async data => {
  let x = data
  let y = await 2

  console.log(x, y)
})

Sign up to request clarification or add additional context in comments.

5 Comments

Your second code block is pretty messed up. await is in the wrong place, => must not have a space between them. await 2 makes no sense.
Well, IMO good answers don't repeat bad code, they correct it and explain why.
Also, it's bad to assign to x and y in a higher scope. That is usually a sign that someone wants to try to use those variables in a higher scope and that usually won't work because the timing of when they are set. If I were you, I'd just remove your second code example. It's not how one should do things.
I understand you have to use await in an async function. I don't understand why they can't just make the global context act as if it is executing in an async function. Would save people having to write ugly boiler plate wrappers like this.
Top-level await is currently available in node.js v13.3+ behind the --harmony-top-level-await flag, but it can only be used in modules (files with *.mjs extension or with *.js accompanied with package.json setting "type": "module"), see this answer for sources
10

As of version 13.3, Node.js support Top-level await.

Top-level await means you can now use await operator outside an async function. So both examples are correct:

(async function() {

  await Promise.resolve(console.log('Hello await!'));

}());

// or

await Promise.resolve(console.log('Hello await!'));

Note: Top-level await only works at the top level of modules. There is no support for classic scripts or non-async functions.

Just keep in mind, that the await operator is used to wait for a Promise. It does NOT matter if you are using an await operator with a value other than a Promise. For example, the name variable in the displayName()` function:

async function displayName() {

  const name = await 'unclexo';

  console.log(name);
}

displayName(); // outputs 'unclexo'

As the value of the name variable is not a Promise, it converts the value to a resolved Promise, and waits for it. It happens under the hood.

The old behavior

MDN doc says

The await operator is used to wait for a Promise. It can only be used inside an async function.

3 Comments

outdated answer
Thanks for notifying me. Updated the answer. Let me know if it is Ok.
"Top-level await means you can now use await operator outside an async function. So both examples are correct" That is not correct. You can use the await keyword on its own (outside of an async function) at the top level of a module. The last sentence is actually a quote from the link you provided.
8

This proposal is currently in stage 3 of the TC39 process. LINK

You can use this feature in Google Chrome and Mozilla Firefox as of now. You can use top level await without async in console.

Top level await in console

https://twitter.com/addyosmani/status/1080365576218759168

Comments

4

since node 10, you can run node process with --experimental-repl-await to allow top level await https://nodejs.org/api/repl.html#repl_await_keyword

Comments

0
async function getTen() {
  return 10;
}

(async () => {
  let ten = await getTen();
  console.log(ten);
})();

Source: https://javascript.plainenglish.io/5-javascript-interview-questions-to-identify-outstanding-developers-859a71c3d7f

Comments

-2

You could wrap all the code in the global scope in an async function.

For example:

// ...global imports...

new Promise (async () => {

  // ...all code in the global scope...

}).then()

3 Comments

gregn3, The purpose of the question was not to use promise chaining using .then() or .catch()
@nmxl You didn't mention this in your question though.
At least it's not zero :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.