Resumo : neste tutorial, você aprenderá sobre o await de nível superior do JavaScript e seus casos de uso.
Introdução à espera de nível superior do JavaScript
ES2020 introduziu o recurso de espera de nível superior que permite que um módulo se comporte como uma async
função. Um módulo que importa o módulo await de nível superior aguardará o carregamento antes de avaliar seu corpo.
Para entender melhor o recurso de espera de nível superior, daremos um exemplo:
Neste exemplo, teremos três arquivos: index.html
, app.mjs
e user.mjs
:
- O
index.html
usa oapp.mjs
arquivo. - O
app.mjs
importa ouser.mjs
arquivo. - Ele
user.mjs
busca os dados do usuário no formato JSON de uma API com o endpoint de URL https://jsonplaceholder.typicode.com/users
Aqui está o arquivo de índice que usa o módulo app.mjs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Top-Level Await Demo</title>
</head>
<body>
<div class="container"></div>
<script type="module" src="app.mjs"></script>
</body>
</html>
Linguagem de código: HTML, XML ( xml )
O seguinte mostra o user.mjs
arquivo:
let users;
(async () => {
const url = 'https://jsonplaceholder.typicode.com/users';
const response = await fetch(url);
users = await response.json();
})();
export { users };
Linguagem de código: JavaScript ( javascript )
O user.mjs
módulo usa a API fetch para obter os usuários no formato JSON de uma API e exportá-los.
Como só podemos usar a await
palavra-chave dentro de uma async
função (antes do ES2020), precisamos agrupar a chamada da API dentro de uma expressão de função assíncrona invocada imediatamente (IIAFE).
O seguinte mostra o app.mjs
módulo:
import { users } from './user.mjs';
function render(users) {
if (!users) {
throw 'The user list is not available';
}
const list = users
.map((user) => {
return `<li> ${user.name}(<a href="email:${user.email}">${user.email}</a>)</li>`;
})
.join('');
return `<ol>${list}</ol>`;
}
const container = document.querySelector('.container');
try {
container.innerHTML = render(users);
} catch (e) {
container.innerHTML = e;
}
Linguagem de código: JavaScript ( javascript )
Como funciona.
Primeiro, importe users
do user.mjs
módulo:
import { users } from './user.mjs';
Linguagem de código: JavaScript ( javascript )
Segundo, crie uma render()
função que renderize a lista de usuários em uma lista ordenada em formato HTML:
function render(users) {
if (!users) {
throw 'The user list is not available.';
}
const list = users
.map((user) => {
return `<li> ${user.name}(<a href="email:${user.email}">${user.email}</a>)</li>`;
})
.join('');
return `<ol>${list}</ol>`;
}
Linguagem de código: JavaScript ( javascript )
Terceiro, adicione a lista de usuários ao elemento HTML com a classe .container
:
const container = document.querySelector('.container');
try {
container.innerHTML = render(users);
} catch (e) {
container.innerHTML = e;
}
Linguagem de código: JavaScript ( javascript )
Se você abrir o index.html
, verá a seguinte mensagem:
The user list is not available.
Linguagem de código: PHP ( php )
O seguinte mostra o fluxo principal:
Neste fluxo:
- Primeiro,
app.mjs
importa ouser.mjs
módulo. - Segundo, o
user.mjs
módulo executa e faz uma chamada de API. - Terceiro, enquanto a segunda etapa ainda está em andamento, ele
app.mjs
começa a usar osusers
dados importados douser.mjs
módulo.
Como a etapa 2 não foi concluída, a users
variável foi undefined
. Portanto, você viu a mensagem de erro na página.
Gambiarra
Para corrigir o problema, você pode exportar um Promise
do user.mjs
módulo e aguardar a conclusão da chamada da API antes de usar seu resultado.
O seguinte mostra a nova versão do user.mjs
módulo:
let users;
export default (async () => {
const url = 'https://jsonplaceholder.typicode.com/users';
const response = await fetch(url);
users = await response.json();
})();
export { users };
Linguagem de código: JavaScript ( javascript )
Nesta nova versão, o modelo user.mjs exporta o users
e a Promise
como exportação padrão.
Nas app.mjs
importações promise
e users
do user.mjs
arquivo e chama then()
o método da promise
seguinte forma:
import promise, { users } from './user.mjs';
function render(users) {
if (!users) {
throw 'The user list is not available.';
}
let list = users
.map((user) => {
return `<li> ${user.name}(<a href="email:${user.email}">${user.email}</a>)</li>`;
})
.join(' ');
return `<ol>${list}</ol>`;
}
promise.then(() => {
let container = document.querySelector('.container');
try {
container.innerHTML = render(users);
} catch (error) {
container.innerHTML = error;
}
});
Linguagem de código: JavaScript ( javascript )
Como funciona.
Primeiro, importe promise
e users
do user.mjs
módulo:
import promise, { users } from './user.mjs';
Linguagem de código: JavaScript ( javascript )
Segundo, chame o then()
método da promessa e aguarde a conclusão da chamada da API para usar seus resultados:
promise.then(() => {
let container = document.querySelector('.container');
try {
container.innerHTML = render(users);
} catch (error) {
container.innerHTML = error;
}
});
Linguagem de código: JavaScript ( javascript )
Agora, se você abrir o index.html
, verá uma lista de usuários. No entanto, você precisa saber a promessa certa de esperar por ela ao usar o módulo.
ES2022 introduziu nesta solução alternativa o módulo de espera de nível superior para resolver esse problema.
Usando o await de nível superior
Primeiro, altere user.mjs
para o seguinte:
const url = 'https://jsonplaceholder.typicode.com/users';
const response = await fetch(url);
let users = await response.json();
export { users };
Linguagem de código: JavaScript ( javascript )
Neste módulo, você pode usar a await
palavra-chave sem colocar uma instrução dentro de uma async
função.
Segundo, importe os usuários do user.mjs
módulo e use-o:
import { users } from './user.mjs';
function render(users) {
if (!users) {
throw 'The user list is not available.';
}
let list = users
.map((user) => {
return `<li> ${user.name}(<a href="email:${user.email}">${user.email}</a>)</li>`;
})
.join(' ');
return `<ol>${list}</ol>`;
}
let container = document.querySelector('.container');
try {
container.innerHTML = render(users);
} catch (error) {
container.innerHTML = error;
}
Linguagem de código: JavaScript ( javascript )
Nesse caso, o app.mjs
módulo aguardará user.mjs
a conclusão do módulo antes de executar seu corpo.
Casos de uso de espera de nível superior de JavaScript
Quando você usa o await de nível superior? Aqui estão alguns casos de uso.
Caminho de dependência dinâmica
const words = await import(`/i18n/${navigator.language}`);
Linguagem de código: JavaScript ( javascript )
Neste exemplo, o await de nível superior permite que os módulos usem valores de tempo de execução para decidir as dependências, o que é útil para os seguintes cenários:
- Internacionalização (i18n)
- Divisões no ambiente de desenvolvimento/produção.
Retorno de dependência
Nesse caso, você pode usar o await de nível superior para carregar um módulo de um servidor (cdn1). E se falhar, você pode carregá-lo de um servidor de backup (cdn2):
let module;
try {
module = await import('https://cdn1.com/module');
} catch {
module = await import('https://cdn2.com/module');
}
Linguagem de código: JavaScript ( javascript )
Resumo
- Um módulo await de nível superior atua como uma
async
função. - Quando um módulo importa um módulo de espera de nível superior, ele aguarda a conclusão do módulo de espera de nível superior antes de avaliar seu corpo.