How to wait for an async function in javascript at top level?

top-level await javascript
typescript top-level await
top-level await support
babel top-level await
top-level await proposal
ts-node top-level await
node top-level await flag
webpack top-level await

I know this is a terrible idea. But I have an API which I can't use until I have a piece of data which I can only get asynchronously. Something like this:

const key = await get_async_data(config) // NOT RIGHT, can't use await at top level
const api = new API(key)
... use api ...

This is at top level, outside of any function, so I can't just await get_async_data() (it does return a Promise). Is there anything short of putting all my code in a giant async function so I can call await?

API is just a class exported by a module (which I control).

(BTW I thought of putting the code to get the key into the API class's constructor, but of course constructors can't be async either.)

I could make every async method of API set the key if unset, but that's pretty invasive and error-prone.

So I'm not really asking how to make my top-level code wait as much as I'm looking for alternative ways to structure this so the async call happens cleanly.

Here's some more detail in case this helps. In api.js:

class API {
  constructor(key) {
    this.key = key
    // other stuff
  }
  async f1(a) {
  }
  async f2(b, c) {
  }
  f3() {
    return true
  }
}
export default API

Then in the places (many) where it'll be used:

import API from '@/api'

const key = async get_key() // NOPE
const theAPI = new API(key)

async importantMethod(args)
{
  return await theAPI.f1(args)
}
async otherMethod()
{
  if (theAPI.f3)
    return await theAPI.f2(123)
  // etc...
}
// ... and so on

top level is a terrible idea, yes. But I don't see why you can't just put it in a function?

const getAsync = async () => {
  const key = await get_async_data(config);
  return key;
}
getAsync().then(key => {
  const api = new API(key)
}

Top-level await, Top-level await. Top-level await enables developers to use the await keyword outside of async functions. It acts like a big async function causing other modules who import them to wait before they start evaluating their body. The keyword Await makes JavaScript wait until the promise returns a result. It has to be noted that it only makes the async function block wait and not the whole program execution.

Just use the Promise:

const pendingAPI = get_async_data(config).then(key => new API(key)); // N.B. no await
export default pendingAPI;

Meanwhile, in another file...

import pendingAPI from 'other/file';
pendingAPI.then(doStuffWithAPI);

There are times when async/await is a win. But never forget it's just sugar over Promises.

How the new 'Top Level Await' feature works in JavaScript, Top-level await enables modules to act like async functions. Modules are asynchronous and have an import and export, and those also� Promises made dealing with asynchronous code easier. ES8 introduced one feature that makes this even easier. This feature is async/await. This tutorial will help you learn about what async/await is and how it works.

If you want to alter your existing code as little as possible, I'd consider changing the entry point to a module which gets the key, and then calls the module which instantiates the API (the old entry point). For example:

// start.js
import makeApi from './makeApi';
get_key()
  .then(makeApi);

// makeApi.js
export default function(key) {
  const theApi = new API(key);
  function importantMethod(args) {
    return theAPI.f1(args)
  }
  function otherMethod() {
    if (theAPI.f3)
      return theAPI.f2(123)
  }
  // etc
}

In short, all you have to do is wrap your current entry point in a function.

Top-level `await` is a footgun � GitHub, Note that await can only be used inside an async function. Top-level await is a proposal to allow await at the top level of JavaScript modules. Top-level await comes to solve this and enables developers to use the await keyword outside async functions. With top-level await, ECMAScript Modules can await resources, causing other modules who

tc39/proposal-top-level-await, top-level `await` proposal for ECMAScript (stage 3) To integrate with the JavaScript module system, they will need to do the equivalent of a top-level await . But at the top level of the code, when we’re outside any async function, we’re syntactically unable to use await, so it’s a normal practice to add .then/catch to handle the final result or falling-through error, like in the line (*) of the example above.

Async/await, The keyword await makes JavaScript wait until that promise settles and returns its syntax error in top-level code let response = await fetch� Top-level code, up to and including the first await expression (if there is one), is run synchronously. 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. For example:

How to use top-level await in ES Modules, v8 recently introduced top-level await for ES modules. some time before this feature will be usable in the production Node.js and in Chrome,� v8 recently introduced top-level await for ES modules. It’s a new proposed standard for ECMAScript, which has reached stage 3. Note: it’s going to take some time before this feature will be usable in the production Node.js and in Chrome, but it’s worth taking a look. Right now we can use await only inside async functions. So it’s common

Comments
  • Can you explain the issue you have with wrapping the code in an async function (or just using .then)? It would seem to be the obvious solution
  • I want to use this API everywhere, in all my classes. I can't wrap everything in a giant async function.
  • Not sure what you mean, but you'd need to await for this function everywhere you need to wait for the promise to resolve before continuing. Or if you dont want to wrap everything in an async function just do use .then instead.
  • Can you give a more concrete example with more code, so we can see what looks too messy to you? It's not all that clear ATM
  • Just call the api, stuff the resulting promise in a var, and await as needed.
  • No need for await / async if you're using .then, just do get_async_data(config).then(key =>
  • Also, it's not so much a "terrible idea" (it's not a bad idea, there's currently a proposal for top-level await) as an idea that's not currently permitted by the spec.
  • sure, but he seems to want a smaller function available to use elsewhere. Maybe to involve other parameters? and whether it's just pure promise or written as async await is neither here nor there.
  • re proposal, I didn't know that, interesting. I would still say that doing any functionality in global is generally to be avoided but I understand there are other POVs on that. I guess top level await would make it feel a bit more PHP / Python-y.
  • Top level in a project doesn't necessarily mean global, luckily - that's what module bundlers are for.