Executando verificação de segurança...
1

5 Lacunas Críticas que Todo Dev JavaScript Ignora (e Como Cobrir Cada Uma)



## O Problema Real

A maioria dos devs JavaScript sabe fazer funcionar. Poucos sabem fazer funcionar **direito**.

Depois de revisar centenas de PRs em projetos open source e mentorar times, identifiquei cinco lacunas que se repetem. Não são bugs óbvios. São buracos silenciosos que explodem em produção.

Este post cobre cada um com código funcional. Sem teoria vazia.

## Lacuna 1: Event Loop e Microtasks Mal Compreendidos

Esse é o gap mais perigoso. Devs escrevem `async/await` sem entender a fila de execução.

Veja este código. Qual a ordem de saída?

```javascript
console.log("1");

setTimeout(() => console.log("2"), 0);

Promise.resolve().then(() => console.log("3"));

queueMicrotask(() => console.log("4"));

console.log("5");

A resposta correta é: 1, 5, 3, 4, 2.

Se você errou, essa lacuna está aberta no seu código. Microtasks (Promises, queueMicrotask) executam antes de macrotasks (setTimeout, setInterval). Isso afeta tudo: ordem de renderização, race conditions, estado inconsistente.

Como cobrir na prática

Crie um scheduler explícito quando a ordem importa:

class TaskScheduler {
  #microtasks = [];
  #macrotasks = [];
  #isProcessing = false;

  addMicrotask(fn, label = "unnamed") {
    this.#microtasks.push({ fn, label });
    this.#scheduleFlush();
  }

  addMacrotask(fn, label = "unnamed") {
    this.#macrotasks.push({ fn, label });
    this.#scheduleFlush();
  }

  #scheduleFlush() {
    if (this.#isProcessing) return;
    this.#isProcessing = true;

    queueMicrotask(() => {
      this.#flush();
      this.#isProcessing = false;
    });
  }

  #flush() {
    // Microtasks primeiro, respeitando a spec
    while (this.#microtasks.length > 0) {
      const task = this.#microtasks.shift();
      console.log(`[micro] ${task.label}`);
      task.fn();
    }

    // Uma macrotask por ciclo, como o browser faz
    if (this.#macrotasks.length > 0) {
      const task = this.#macrotasks.shift();
      console.log(`[macro] ${task.label}`);
      setTimeout(() => {
        task.fn();
        if (this.#macrotasks.length > 0) this.#scheduleFlush();
      }, 0);
    }
  }
}

// Uso
const scheduler = new TaskScheduler();
scheduler.addMacrotask(() => fetch("/api/logs"), "send-logs");
scheduler.addMicrotask(() => updateUI(), "ui-update");

Esse padrão torna a ordem de execução visível e testável. Sem surpresas.

Lacuna 2: Memory Leaks em Closures e Event Listeners

JavaScript tem garbage collector. Mas ele não é mágico.

O leak mais comum? Closures que capturam referências gigantes sem necessidade.

// ❌ Leak: handler mantém referência ao array inteiro
function setupSearch(hugeDataset) {
  const searchInput = document.getElementById("search");

  searchInput.addEventListener("input", (e) => {
    // hugeDataset (10MB) nunca será coletado enquanto
    // o listener existir
    const results = hugeDataset.filter((item) =>
      item.name.includes(e.target.value)
    );
    renderResults(results);
  });
}

O hugeDataset fica preso na closure. Mesmo que você nunca mais precise dele inteiro.

A correção real

// ✅ Sem leak: WeakRef + cleanup explícito
function setupSearch(hugeDataset) {
  const searchInput = document.getElementById("search");

  // Pré-processa: cria índice leve
  const searchIndex = new Map();
  for (const item of hugeDataset) {
    const key = item.name.toLowerCase();
    if (!searchIndex.has(key)) {
      searchIndex.set(key, []);
    }
    searchIndex.get(key).push(item.id);
  }

  // hugeDataset pode ser coletado agora
  const controller = new AbortController();

  searchInput.addEventListener(
    "input",
    (e) => {
      const query = e.target.value.toLowerCase();
      const matchedIds = [];

      for (const [key, ids] of searchIndex) {
        if (key.includes(query)) matchedIds.push(...ids);
      }

      renderResults(matchedIds);
    },
    { signal: controller.signal }
  );

  // Cleanup quando necessário
  re

---

Leia o artigo completo em [https://vivodecodigo.com.br/backend/lacunas-criticas-javascript-opensource-webdev](https://vivodecodigo.com.br/backend/lacunas-criticas-javascript-opensource-webdev)
Carregando publicação patrocinada...