What are the precautions to be taken when using top-level await in Javascript?

Asked

Viewed 313 times

14

To proposal for the top-level await has just been completed, which means that this feature will soon be part of the language.

As far as I know, this feature will only be available when executed in the context of modules (as well as the statements import and export).

Like the await is an over-used feature by many developers, would like to know what are, punctually, the precautions to be taken when using the top-level await.

1 answer

7


The top-level await (TLA) is a new Javascript feature that allows operator usage await in the higher scope of Ecmascript modules (ESM). This higher scope is called top-level.

The behavior of await in the module top-level is the same as when it is used in asynchronous functions. In short:

  • In case the promise is resolved, the await returns the resolution value.
  • In case the promise is rejected, await launches the rejection value.

What justifies the top-level await?

In some cases, it may be necessary to load some resource asynchronously during a module startup. In order for this to be done on its own, the exports of the module, in the ideal world, should not be effected until all asynchronous startup work has been completed.

That’s what, basically, the top-level await resolve. When used in module top-level, prevent the execution of the rest of the module (including the exports of the module) until the promise has been resolved.

This ensures that the module will only export its content when all the promises awaited on top-level have been resolved or any of them have been rejected. This "short-circuit" behavior is similar to Promise.all.

Of course this feature should not be overused (we will see below some negative points of doing this resource initialization asynchronously). But when necessary, it can certainly be quite useful. The proposal repository (still in stage three) mentions some cases of use in which the top-level await can make sense.

What are the precautions to be taken when using the top-level await?

1. The top-level await crashes a module and its descendants

This may be the worst problem facilitated for top-level await. I must point out that the problem is not due to the TLA itself, but due to the fact of asynchronous resource loading on the top-level module.

There’s no way out of this - if a module To does asynchronous boot, it will lock until the completion of the awaited promises. And, because of this lock, all other modules that import To (using the syntax import ... from 'A') will also be stopped.

This locking by progeny can be extremely prolonged in long import chains. In some cases, use Dynamic Imports can avoid this problem if the module can be loaded so Lazy.

Supposing a.mjs contains some kind of asynchronous boot, this module, which depends on A, will also be locked:

// Só será executado quando `A` terminar a inicialização...
import * as A from './a.mjs';

console.log(A);

But if the import is made using Dynamic import, which is asynchronous, this module will not be locked. Note that in this case the import must be done within an asynchronous function. If the await be done in top-level, the behaviour would be the same as in the previous example.

// Note agora que o carregamento do módulo `A` é lazy.
// Desse modo, este módulo não será bloqueado em detrimento de `A`.
//
// O módulo `A` será carregado somente quando a função `doStuff` for invocada.
export async function doStuff() {
  const A = await import('./a.mjs');
  console.log(A);
}
  • 1

    I haven’t finished yet, but the time is half over. In a full time the answer. Nevertheless, what is already there is what I think is the most important.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.