/** * Parte 4 — Sequencial × concorrente. * * npx tsx src/05-sequencial-concorrente.ts * * A pergunta que decide entre os dois é sempre a mesma: **a segunda chamada * precisa do resultado da primeira?** */ import { buscarLivro, contarEmprestimosAbertos, cronometro } from './biblioteca.js'; // --------------------------------------------------------------------------- // Dependência real: o total de empréstimos precisa do id que veio da busca. // Aqui o `await` sequencial é obrigatório, e o custo é o esperado. // --------------------------------------------------------------------------- async function dependenciaReal(): Promise { const marcar = cronometro(); const livro = await buscarLivro(1); const total = await contarEmprestimosAbertos(livro.id); marcar(`dependência real : ${livro.titulo} — ${total} em aberto`); } // --------------------------------------------------------------------------- // Dependência falsa: os três livros são independentes. Escrito em sequência, // o programa paga a soma dos tempos sem nenhuma razão. // --------------------------------------------------------------------------- async function tresEmSequencia(): Promise { const marcar = cronometro(); const primeiro = await buscarLivro(1); const segundo = await buscarLivro(2); const terceiro = await buscarLivro(3); marcar(`sequencial : ${[primeiro, segundo, terceiro].length} livros`); } async function tresConcorrentes(): Promise { const marcar = cronometro(); const livros = await Promise.all([buscarLivro(1), buscarLivro(2), buscarLivro(3)]); marcar(`Promise.all : ${livros.length} livros`); } // --------------------------------------------------------------------------- // O mesmo erro dentro de um laço — a forma mais comum de encontrá-lo. // --------------------------------------------------------------------------- async function lacoSequencial(ids: number[]): Promise { const marcar = cronometro(); const titulos: string[] = []; for (const id of ids) { const livro = await buscarLivro(id); // await dentro do laço titulos.push(livro.titulo); } marcar(`laço com await : ${titulos.length} títulos`); } async function lacoConcorrente(ids: number[]): Promise { const marcar = cronometro(); // `map` devolve um vetor de promises — todas já em andamento. `Promise.all` // apenas espera pelo conjunto. const titulos = await Promise.all(ids.map(async (id) => (await buscarLivro(id)).titulo)); marcar(`map + Promise.all : ${titulos.length} títulos`); } async function principal(): Promise { await dependenciaReal(); await tresEmSequencia(); await tresConcorrentes(); await lacoSequencial([1, 2, 3, 4]); await lacoConcorrente([1, 2, 3, 4]); } void principal(); /** * Duas leituras erradas de `Promise.all` que vale desfazer: * * - Ele **não** dispara as chamadas. As promises do vetor já estavam em * andamento antes de `Promise.all` ser chamado — quem dispara é a chamada da * função. `Promise.all` só decide o momento de continuar. * - Ele **não** cria threads. Continua havendo uma linha de execução; o que se * sobrepõe é a espera, que é onde o tempo estava sendo gasto. A diferença * entre isso e paralelismo de verdade está no exemplo 11. * * E uma consequência: `Promise.all` rejeita assim que UMA das promises * rejeita, sem esperar as outras — que continuam correndo até o fim, sem * ninguém observando o resultado. Quando isso importa, o combinador certo é * `allSettled` (Parte 6). */