Cliente web e desempenho

HTML, CSS, JavaScript e pedidos assíncronos, com medidas e diagnóstico do tempo de resposta.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

A lista de sessões pode demorar por causa do SQL, da transferência ou do trabalho do navegador. O servidor produz a resposta; o navegador constrói o DOM a partir do HTML, aplica CSS e executa JavaScript. Mede essas parcelas antes de escolher a intervenção, para não melhorar um recurso que pouco pesa no tempo observado.

Estrutura, apresentação e comportamento

HTML descreve estrutura e significado, como títulos, links e formulários. CSS define apresentação e disposição. JavaScript responde a eventos e altera o documento. Um botão nativo já suporta ativação por teclado; substituir tudo por elementos genéricos exige reconstruir comportamentos e nomes acessíveis.

Um seletor CSS escolhe elementos; a cascata combina origem, importância, especificidade e ordem, entre outras regras. No box model, largura de conteúdo, padding, border e margin não são a mesma coisa. Com box-sizing: border-box, a largura declarada inclui padding e border. Um layout responsivo adapta-se ao espaço disponível sem depender de uma lista fechada de modelos de telefone.

O DOM é a representação do documento como uma árvore de nós. addEventListener associa um comportamento a um evento. O comportamento deve ler o estado atual, atualizar o necessário e preservar foco e mensagens. Insere texto com textContent para o manter como texto, porque inserir HTML muda o contexto e pode criar XSS.

HTML semântico e seletores CSS

Um menu de ligações pode ser uma lista dentro de nav. O sentido vem do HTML; CSS escolhe a disposição horizontal ou vertical:

<nav aria-label="Área pessoal">
  <ul>
    <li class="destaque"><a href="/bilhetes">Bilhetes</a></li>
    <li><a href="/perfil">Perfil</a></li>
  </ul>
</nav>
SeletorElementos escolhidos no exemplo
.destaqueO primeiro li, que tem essa classe.
.destaque aO link descendente desse li.
li.destaqueElementos li com essa classe.
nav > ulA lista filha direta de nav.
nav + ulUma lista imediatamente depois de nav, com o mesmo pai; nenhuma aqui.

Espaço significa descendência, > exige filho direto e + exige irmão seguinte. li.destaque não é o mesmo que li .destaque: o segundo procura um descendente com a classe.

Numa tabela de dados, th marca uma célula de cabeçalho; td marca dados. Num caso simples, usa <th scope="col">Preço</th> para ligar um cabeçalho à coluna. caption identifica a tabela. Estes elementos não significam o cabeçalho geral da página.

Âmbito de var, let e const

Dentro de uma função, var tem âmbito da função; let e const têm âmbito do bloco. Uma declaração var é conhecida antes da linha que a inicializa, com valor undefined. let e const não podem ser usados antes da sua inicialização. const impede reatribuir a ligação, mas não congela um objeto.

Ler os limites dos blocos e do modo estrito
'use strict';

function resumo() {
  if (true) {
    var total = 8;
    let parcial = 3;
    console.log(parcial);
  }
  console.log(total);
  console.log(typeof parcial);
}

console.log(typeof total);
resumo();
try {
  pendente = 7;
} catch (erro) {
  console.log(erro.name);
}
Resultado

Executa o código para ver a saída e os gráficos.

total é local à função, mas pode ser usado depois do if. parcial só existe dentro do bloco. Fora dele, typeof de um nome sem ligação dá a string "undefined"; tentar ler esse nome diretamente daria um erro.

Em scripts antigos não estritos, atribuir a um nome sem declaração pode criar uma propriedade global. Neste programa, "use strict" impede a atribuição a pendente e gera ReferenceError. Módulos JavaScript já são estritos. Uma resposta sobre código antigo precisa de identificar se é um script clássico ou um módulo.

Pedidos assíncronos e estados da interface

AJAX designa técnicas que pedem dados e atualizam partes de uma página sem uma navegação completa. Apesar do nome histórico Asynchronous JavaScript and XML, a resposta pode conter JSON, HTML, XML ou outro formato definido pela API. Não é um processo de background do servidor. Com fetch, escolhe json() ou text() conforme o corpo e o contrato do recurso.

Este fragmento pressupõe uma página que tem um elemento #resultado e uma API no mesmo site:

async function carregarSessao(id) {
  const resultado = document.querySelector('#resultado');
  resultado.textContent = 'A carregar';
  try {
    const resposta = await fetch(`/api/sessoes/${encodeURIComponent(id)}`);
    if (!resposta.ok) throw new Error(`HTTP ${resposta.status}`);
    const sessao = await resposta.json();
    resultado.textContent = `${sessao.titulo}: ${sessao.livres} lugares`;
  } catch {
    resultado.textContent = 'Não foi possível carregar a sessão.';
  }
}

fetch pode resolver a promise mesmo quando recebe 404 ou 500. Verifica ok ou o código; uma rejeição da promise pode representar uma falha de rede. O formato do corpo também pode estar errado, e json() pode falhar. Trata carregamento, sucesso, vazio e falha como estados diferentes.

Se duas pesquisas são lançadas em sequência, a resposta antiga pode chegar depois da nova. Cancela pedidos ultrapassados com AbortController ou associa cada resposta a um identificador de pedido e só aplica a mais recente. A ordem em que envias pedidos não garante a ordem de chegada.

Uma interface assíncrona não dispensa autorização no servidor. A pessoa pode enviar a mesma operação por outro cliente. O valor «lugares livres» mostrado pode mudar antes de a compra confirmar; a transação coordenada continua a ser necessária.

Dividir o tempo observado

Para um modelo simplificado de pedido sem sobreposição, consideremos 20 ms de aplicação, 80 ms de SQL, 50 ms de rede e 30 ms até apresentar o resultado. São 180 ms. Um índice que reduz SQL para 20 ms reduz o total para 120 ms, não para 45 ms. A melhoria local de quatro vezes não se propaga automaticamente a todo o percurso.

Na prática, alguns trabalhos sobrepõem-se e há esperas em filas. Mede tempo até ao primeiro byte, transferência, renderização e resposta à interação. Latência é demora por operação; throughput é operações por unidade de tempo. Aumentar concorrência pode aumentar throughput até saturar um recurso e, depois, aumentar a latência.

Calcular o p95 à mão e localizar o limite

Ordena vinte medidas: dez de 50 ms, nove de 100 ms e uma de 500 ms. A soma é 10 × 50 + 9 × 100 + 500 = 1900 ms e a média é 1900 / 20 = 95 ms.

Pelo método nearest-rank, o p95 ocupa a posição ceil(0,95 × 20) = 19. As posições 11 a 19 valem 100 ms, por isso o p95 é 100 ms. Neste conjunto, 19 das 20 observações ficam iguais ou abaixo desse valor. O máximo de 500 ms mostra um pedido lento que a média e o p95 não descrevem sozinhos.

Posições na amostra ordenadaTempoQuantidade
1 a 1050 ms10
11 a 19, incluindo o p95100 ms9
20500 ms1

Declara amostra, carga, rede e método de cálculo ao comparar medições. O ganho do modelo anterior é 180 / 120 = 1,5 no percurso completo, apesar da redução de quatro vezes no SQL.

Melhorar o recurso que limita o percurso

Causa observadaIntervenção a testar
Muitas consultas por páginaResolver N+1, agrupar dados e limitar a projeção.
SQL lento e seletivoAnalisar plano e um índice adequado.
Muitos bytes de imagensDimensões adequadas, formatos eficientes e compressão.
Recursos que bloqueiam a apresentaçãoReduzir o caminho crítico; adiar trabalho que não é necessário ao primeiro conteúdo.
Script longo sem resposta a eventosReduzir trabalho, dividir tarefas ou usar Worker quando o cálculo o permitir.
Conteúdo público repetidoCache com invalidação e política adequadas.

O navegador transforma HTML e CSS em árvores, calcula estilos e layout, pinta e compõe. Uma alteração de geometria pode exigir novo layout; alternar repetidamente leitura e escrita de geometria pode forçar trabalho síncrono. «Usar JavaScript» não identifica a causa, é preciso observar a operação.

Cachear uma resposta privada como pública pode expor dados. Carregar tudo antecipadamente pode desperdiçar transferência. Lazy loading faz sentido para recursos que não são necessários já, mas adiar o elemento principal da página pode atrasar a apresentação. Testa o efeito na tarefa, não só o tamanho de um ficheiro.

Exercícios

Selecionar o link dentro do item

Num menu nav com ul e li, a classe destaque está no li. Que seletor seleciona os links dentro desse item?

A tua resposta

Pista

Uma classe colada ao nome do elemento pertence a esse elemento.

Mais uma pista

O espaço seguinte procura descendentes.

Solução

li.destaque a. O li tem a classe e o a está dentro dele. nav descreve a região de navegação e ul a lista; o seletor trata a apresentação.

  • li.destaque a. Seleciona os links descendentes do li com essa classe.
  • li .destaque. Procura a classe num descendente do li, não no próprio li.
  • li + a. Procura um a que seja o irmão imediatamente seguinte do li.

Erros frequentes

Um espaço muda a relação entre os elementos, não é apenas formatação.

Voltar à explicação
Distinguir bloco e função

Dentro de uma função em modo estrito, um if declara var a=2 e let b=5. Depois do if, quais podes ler pelo nome? Que acontece com c=9 se c nunca foi declarado?

Pista

O bloco do if termina antes da função.

Mais uma pista

Modo estrito não cria uma variável global implícita.

Solução

a continua no âmbito da função; b só existe no bloco. Ler b diretamente fora dá ReferenceError. A atribuição a c também dá ReferenceError. O typeof de um nome completamente não declarado é um caso especial que pode dar 'undefined'.

Confere a tua resposta:

  • var permanece visível na função após o bloco.
  • let pertence ao bloco.
  • Uma atribuição a nome não declarado falha em modo estrito.

Erros frequentes

Não confundas ausência de uma variável com uma variável declarada que contém undefined.

Voltar à explicação
Escolher o leitor do corpo

Um endpoint acordado devolve um fragmento HTML. Um pedido assíncrono da página tem de usar resposta.json()?

A tua resposta

Pista

A letra X do nome histórico não limita os formatos.

Mais uma pista

json() tenta analisar JSON; text() devolve texto.

Solução

Não. Pode usar text() e atualizar uma região. O HTML recebido tem de vir de uma fonte confiável e estar protegido contra XSS; receber texto não torna qualquer inserção HTML segura.

  • Pode usar text() e atualizar a região prevista.. AJAX não exige XML nem JSON; o contrato pode devolver HTML.
  • Tem obrigatoriamente de usar json().. O método tem de corresponder ao corpo recebido.
  • Tem de recarregar a página inteira.. O pedido pode atualizar uma parte do documento.

Erros frequentes

Não interpretes um erro de análise de JSON como prova de que o pedido HTTP nunca teve resposta.

Voltar à explicação
Somar o modelo do percurso

Num modelo sequencial, aplicação 20 ms+SQL 80 ms+rede 50 ms+apresentação 30 ms. Reduzir SQL para 20 ms dá que total, em ms?

Pista

Só mudou uma parcela.

Mais uma pista

20+20+50+30.

Solução

O total é 120 ms. O SQL melhorou quatro vezes, mas o percurso completo passou de 180 para 120 ms.

Erros frequentes

Não multipliques o ganho local por todas as parcelas.

Voltar à explicação
Resposta HTTP e falha de rede

fetch de um endpoint que responde 404 rejeita obrigatoriamente a promise?

A tua resposta

Pista

Houve uma resposta, embora de erro.

Mais uma pista

Usa resposta.ok ou resposta.status.

Solução

Não rejeita obrigatoriamente. Verifica o código; a rede e a análise do corpo têm outros modos de falha.

  • Não. É preciso verificar o estado HTTP.. Uma resposta HTTP de erro pode resolver a promise.
  • Sim, todos os erros HTTP são rejeições.. Não é o contrato de fetch.
  • Não, 404 prova sucesso do recurso.. A promise resolvida não torna o código 200.

Erros frequentes

Não escrevas um catch que nunca observa os códigos HTTP inválidos.

Voltar à explicação
Não aplicar uma resposta antiga

Envias pesquisa A e depois B. A chega por último. Como impedir que substitua os resultados B?

Pista

O envio e a receção têm ordens diferentes.

Mais uma pista

AbortController ou um identificador de pedido pode resolver.

Solução

Cancela A e trata o cancelamento, ou verifica um identificador crescente antes de aplicar cada resposta. Só a pesquisa atual altera o estado.

Confere a tua resposta:

  • Associo respostas ao pedido.
  • Só aplico a resposta atual ou cancelo A.
  • Não uso a ordem de chegada como ordem de intenção.

Erros frequentes

Debounce sozinho reduz pedidos, mas não demonstra que a resposta antiga não será aplicada.

Voltar à explicação
Calcular o p95 nearest-rank

Com dez medidas de 50 ms, nove de 100 ms e uma de 500 ms, qual é o p95 nearest-rank em ms?

Pista

Ordena e conta a posição ceil(0,95 x 20).

Solução

A posição é ceil(0,95 × 20) = 19. As posições 11 a 19 valem 100 ms, logo p95 = 100 ms. A observação de 500 ms está na posição 20 e não determina este percentil.

Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.