Capítulo 22
JavaScript assíncrono
3 min de leitura 527 palavras 1 gravura
Trabalhe numa cópia da pasta inicio/ desta etapa. Ela já abre ou executa com as instruções do README. Leia o código, mude uma coisa e anote sua previsão antes de recarregar. Compare com a referência na pasta da etapa. Se nada mudar, confira a extensão do arquivo, o arquivo salvo e o caminho aberto. Blocos adicionais do capítulo são experiências separadas; a pasta de referência contém o programa completo desta etapa.
A Biblioteca da Ribeira, acervo comunitário fictício no bairro da Ribeira, Recife, lista títulos sem travar a página. O pedido vai ao arquivo livros.json. A resposta chega depois. Enquanto isso, a visitante ainda pode clicar.
O exemplo está em exemplos/22-javascript-assincrono/. Sirva a pasta em 127.0.0.1. O ciclo: ler, copiar, mudar uma coisa, prever, recarregar, conferir.
O que você vai aprender
- O que significa código bloqueante.
- Ler uma promessa nos três estados.
- Usar
async/awaitefetch. - Abrir
livros.jsonsó com servidor local. - Saber o que é um worker, sem escrever um.
Código que trava a página
JavaScript no navegador, neste volume, roda numa linha. Se uma tarefa demora e espera no mesmo lugar, a página congela. Clique não responde. Isso é bloqueio.
Buscar um arquivo pela rede demora. Por isso o pedido não espera “na frente” da visitante. Ele segue em paralelo. Quando a resposta chega, o código continua.
Promessa: espera, certo, erro
Uma promessa é um objeto que representa um resultado futuro. Três estados: esperando (pending), deu certo (fulfilled), falhou (rejected).

Você não “abre” a promessa na hora. Você diz o que fazer depois, se der certo, e o que fazer se falhar.
async/await e fetch
fetch pede um recurso e devolve uma promessa. async marca a função. await espera o resultado sem travar o restante da página do mesmo jeito que um laço infinito travaria.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Busca assíncrona</title>
</head>
<body>
<h1>Buscar títulos</h1>
<p>Sirva esta pasta em 127.0.0.1.</p>
<button type="button" id="buscar">Buscar</button>
<ul id="lista"></ul>
<script src="busca.js"></script>
</body>
</html>
document.getElementById("buscar").addEventListener("click", async function () {
const lista = document.getElementById("lista");
lista.textContent = "Buscando…";
try {
const resposta = await fetch("livros.json");
const livros = await resposta.json();
lista.innerHTML = "";
livros.forEach(function (livro) {
const item = document.createElement("li");
item.textContent = livro.titulo;
lista.appendChild(item);
});
} catch (erro) {
lista.textContent = "Falhou. Use o servidor local.";
}
});
livros.json nesta pasta:
[{"titulo":"Maré Alta"},{"titulo":"Caderno do Cais"}]
Na pasta principal do volume, que contém a subpasta curso:
python -m http.server 8765 --bind 127.0.0.1 --directory curso
Abra http://127.0.0.1:8765/exemplos/22-javascript-assincrono/. Clique em Buscar. Preveja o aviso “Buscando…” antes da lista. Confira.
Worker, só a ideia
Um worker é outro fio de execução. Serve para conta pesada sem congelar o desenho da página. Neste volume você não cria worker. Basta o nome e o motivo.
Erro comum: abrir index.html pelo disco (file://) e esperar o fetch. Muitos navegadores bloqueiam. Use 127.0.0.1. Não use 0.0.0.0.
Arquivo no disco é JSON e JS. A janela pede. O servidor local responde. Publicação é outro passo, que este capítulo não pede.
Atividades
- Por que a página mostra “Buscando…” antes dos títulos?
- O que muda se
livros.jsonnão existir? - Worker resolve o mesmo problema que
await fetch?
Respostas comentadas
- O clique dispara o pedido e segue. O texto avisa que a resposta ainda não chegou. Sem isso, a lista parece morta.
fetchrejeita ou a leitura falha. Ocatchtroca o aviso. A página não precisa travar.- Não.
fetchespera rede. Worker isola cálculo pesado noutro fio. São ferramentas diferentes. Aqui só o conceito do worker.
O arquivo completo
Referência do exemplo 22-javascript-assincrono, reproduzida aqui para que você possa conferir sem sair da página.
index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<title>Busca assíncrona</title>
<style>
/* Apoio de leitura, teclado e tela estreita. */
img{max-width:100%;height:auto} html {overflow-wrap:anywhere} main {min-width:0} input,textarea,select,canvas {max-width:100%;box-sizing:border-box} fieldset {min-width:0}
pre {max-width:100%;overflow:auto} :focus-visible {outline:3px solid #0f3d3e;outline-offset:3px}
.skip {position:absolute;top:-5rem;left:1rem;background:#0f3d3e;color:white;padding:.5rem;z-index:9}.skip:focus {top:.5rem}
table {max-width:100%} td,th {overflow-wrap:anywhere}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
</style></head>
<body><a class="skip" href="#conteudo">Pular para o conteúdo</a><main id="conteudo" tabindex="-1">
<h1>Buscar títulos</h1>
<p>Sirva esta pasta em 127.0.0.1.</p>
<button id="buscar" type="button">Buscar</button>
<ul id="lista"></ul>
</main><script src="busca.js"></script></body>
</html>
busca.js
document.getElementById("buscar").addEventListener("click", async function () {
const lista = document.getElementById("lista");
lista.textContent = "Buscando…";
try {
const resposta = await fetch("livros.json");
if (!resposta.ok) throw new Error("HTTP " + resposta.status);
const livros = await resposta.json();
if (!Array.isArray(livros)) throw new Error("Formato inesperado");
lista.innerHTML = "";
if (!Array.isArray(livros)) throw new Error("Formato inesperado");
if (!livros.length) lista.textContent = "Nenhum livro nesta lista.";
livros.forEach(function (livro) {
const item = document.createElement("li");
item.textContent = livro.titulo;
lista.appendChild(item);
});
} catch (erro) {
lista.textContent = "Falhou. Use o servidor local.";
}
});