Pular para o conteúdo
murad.guide

As Três Camadas

Capítulo 22

Pedidos à rede

4 min de leitura 654 palavras 1 gravura

Até agora o JavaScript lia o que já estava no HTML. Às vezes a lista mora em outro arquivo. Um pedido à rede busca esse arquivo depois que a página abriu. O nome antigo disso é AJAX; o verbo moderno no navegador é fetch.

Neste capítulo o pedido é local: oficinas.json na mesma pasta. Não chame API pública ainda. Isso fica para o capítulo 23.

O exemplo está em exemplos/22-ajax/. Não abra pelo disco (file://). O navegador bloqueia fetch nesse modo. Sirva em 127.0.0.1.

Trabalhe na cópia inicio desta etapa. Leia e digite o código indicado; mude apenas uma coisa. Antes de recarregar, escreva o resultado que espera. Depois compare com a referência completa ao lado. Se algo falhar, confira primeiro o arquivo salvo e o caminho aberto.

O que você vai aprender

JSON na pasta da oficina

JSON (JavaScript Object Notation) é texto com cara de objeto. Aspas duplas nas chaves. Sem funções. Sem comentários.

[
  { "nome": "Cerâmica", "dia": "sábado" },
  { "nome": "Xilogravura", "dia": "domingo" },
  { "nome": "Fotografia", "dia": "quarta" }
]

O arquivo chama oficinas.json. O script pede esse nome relativo à página.

const resposta = await fetch("oficinas.json");
const oficinas = await resposta.json();

fetch devolve uma promessa: um valor que ainda vai chegar. await pausa a função async até a resposta vir. resposta.json() lê o corpo e monta o array.

Se a página foi aberta como arquivo, o pedido costuma falhar. A mensagem de erro do exemplo avisa para usar o servidor.

Erro comum: duplo clique em index.html e achar que o JSON “não existe”. Ele existe no disco. O que falta é HTTP local.

Pedido local a oficinas.json em 127.0.0.1; file:// costuma bloquear

Sirva em 127.0.0.1

Na pasta curso deste material:

python -m http.server 8769 --bind 127.0.0.1 --directory curso

Visite http://127.0.0.1:8769/exemplos/22-ajax/. Encerre o servidor com Ctrl+C.

127.0.0.1 é esta máquina. Não use 0.0.0.0. Não publique este JSON.

Pare e experimente. Abra a mesma pasta pelo Explorador (barra começando com file://) e recarregue. A lista deve falhar. Volte ao endereço 127.0.0.1 e a lista deve aparecer.

then versus async/await

As duas formas esperam a mesma promessa. A de .then encadeia funções. A de await parece código em fila.

fetch("oficinas.json")
  .then((resposta) => {
    if (!resposta.ok) throw new Error("não achei o JSON");
    return resposta.json();
  })
  .then((oficinas) => {
    oficinas.forEach((oficina) => {
      const item = document.createElement("li");
      item.textContent = `${oficina.nome} — ${oficina.dia}`;
      document.getElementById("lista").append(item);
    });
  })
  .catch((falha) => {
    console.error(falha);
  });

A versão do exemplo usa async / await e try / catch:

async function carregar() {
  const lista = document.getElementById("lista");
  const erro = document.getElementById("erro");
  try {
    const resposta = await fetch("oficinas.json");
    if (!resposta.ok) throw new Error("não achei o JSON");
    const oficinas = await resposta.json();
    oficinas.forEach((oficina) => {
      const item = document.createElement("li");
      item.textContent = `${oficina.nome} — ${oficina.dia}`;
      lista.append(item);
    });
  } catch (falha) {
    erro.hidden = false;
    erro.textContent = "Não deu para ler o JSON. Use o servidor em 127.0.0.1.";
    console.error(falha);
  }
}

carregar();

await só funciona dentro de async function. Lá em cima do arquivo, fora de função, este volume não usa await.

resposta.ok é falso em 404 (arquivo errado). Sem esse if, você tentaria ler HTML de erro como se fosse JSON.

O que catch segura

Rede falhou, arquivo sumiu, JSON malformado: tudo cai no catch. Mostre uma frase na página. Não deixe a falha só no console.

Não peça ainda https://... de um site público. Primeiro o JSON da pasta tem que listar as três oficinas. Quando isso estiver firme, o capítulo 23 usa uma API só como fonte de imagens.

Erro comum: concatenar o endereço file:///B:/.../oficinas.json na mão. fetch relativo ("oficinas.json") basta quando a página e o JSON estão no mesmo diretório servido por HTTP.

Atividades

  1. O que await resposta.json() devolve neste exemplo?
  2. Por que carregar precisa ser async?
  3. Qual endereço você cola na barra para este exercício funcionar?
  4. Renomeie o JSON para agenda.json sem mudar o script. O que a página deve mostrar?

Respostas comentadas

  1. Um array de três objetos, cada um com nome e dia. A partir daí é o mesmo JavaScript do capítulo 17.
  2. Porque ela usa await. Sem async, o arquivo nem carrega: o navegador aponta erro de sintaxe.
  3. http://127.0.0.1:8769/exemplos/22-ajax/ (a porta segue o comando que você usou). Não é file://.
  4. A lista vazia e o parágrafo de erro visível. O fetch continua pedindo oficinas.json, que não está mais nesse nome.

Referências

O arquivo completo

Referência do exemplo 22-ajax, 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>Pedidos à rede</title>
<link href="lab.css" rel="stylesheet"/>
<style>body{overflow-wrap:anywhere}img,input,textarea,select,iframe{max-width:100%}img{height:auto}fieldset,.cartao{min-width:0}pre{max-width:100%;overflow:auto}:focus-visible{outline:3px solid #005fcc;outline-offset:3px}.atalho-conteudo{position:absolute;left:.5rem;top:-6rem;background:white;color:#172f50;padding:.5rem;z-index:999}.atalho-conteudo:focus{top:.5rem}@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}</style></head>
<body><a class="atalho-conteudo" href="#conteudo">Pular para o conteúdo</a><main id="conteudo" tabindex="-1">
<h1>Lista vinda de um JSON</h1>
<p>Sirva esta pasta em 127.0.0.1. Abrir pelo disco costuma bloquear o fetch.</p>
<ul id="lista"></ul>
<p class="fail" hidden="" id="erro"></p>

</main><script src="script.js"></script></body>
</html>

script.js

async function carregar() {
  const lista = document.getElementById("lista");
  const erro = document.getElementById("erro");
  try {
    const resposta = await fetch("oficinas.json");
    if (!resposta.ok) throw new Error("não achei o JSON");
    const oficinas = await resposta.json();
    oficinas.forEach((oficina) => {
      const item = document.createElement("li");
      item.textContent = `${oficina.nome} — ${oficina.dia}`;
      lista.append(item);
    });
  } catch (falha) {
    erro.hidden = false;
    erro.textContent = "Não deu para ler o JSON. Use o servidor em 127.0.0.1.";
    console.error(falha);
  }
}

carregar();