Todos os artigos
74 artigos · atualizado semanalmente Veja nossas Ferramentas
Todos os artigos
Tutoriais

Convertendo CSV gigantes para JSON sem travar a aba

Streams, Web Workers e um truque de chunking que mantém o conversor responsivo mesmo com 200MB de dados.

COVER · Tutoriais

Recebi um CSV de 180MB de dados de transações financeiras e precisava convertê-lo para JSON para processar em uma pipeline. A primeira abordagem travou a aba depois de uns 20 segundos. A segunda também. A terceira funcionou, e é o que vou descrever aqui.

O problema com conversores ingênuos não é o algoritmo — é bloquear a main thread enquanto processa.

Por que a aba trava

Quando você faz FileReader.readAsText(file) e processa tudo em memória na main thread, você está competindo com o loop de eventos do navegador. Para arquivos grandes, esse processamento dura tempo suficiente para o browser parar de responder a inputs e animações.

A solução tem dois eixos: chunking (processar em pedaços) e Web Workers (processar fora da main thread).

Chunking com FileReader

Em vez de ler o arquivo inteiro de uma vez, leia em pedaços:

const CHUNK_SIZE = 2 * 1024 * 1024; // 2MB por vez
let offset = 0;

function readNextChunk() {
  const slice = file.slice(offset, offset + CHUNK_SIZE);
  const reader = new FileReader();
  reader.onload = (e) => {
    processChunk(e.target.result);
    offset += CHUNK_SIZE;
    if (offset < file.size) {
      setTimeout(readNextChunk, 0); // cede o controle ao loop de eventos
    } else {
      finalize();
    }
  };
  reader.readAsText(slice);
}

O setTimeout(readNextChunk, 0) é o truque. Ele não espera nenhum tempo — mas cede o controle ao loop de eventos do browser antes de processar o próximo chunk. Isso mantém a UI responsiva.

Movendo para um Web Worker

Chunking resolve a responsividade, mas o processamento ainda acontece na main thread. Para arquivos acima de ~50MB, mova tudo para um Worker:

// main.js
const worker = new Worker('/csv-worker.js');
worker.postMessage({ file }); // File é transferível
worker.onmessage = (e) => {
  if (e.data.type === 'progress') updateProgress(e.data.percent);
  if (e.data.type === 'done') handleResult(e.data.json);
};

// csv-worker.js
self.onmessage = async (e) => {
  const { file } = e.data;
  const text = await file.text();
  const json = parseCSV(text);
  self.postMessage({ type: 'done', json });
};

Com isso, o parsing acontece em uma thread separada e a main thread nunca bloqueia, independente do tamanho do arquivo.

O problema do header

Chunking tem um efeito colateral: a primeira linha do CSV (o header com os nomes das colunas) precisa ser processada antes de qualquer linha de dados. Guarde os headers do primeiro chunk e use-os para montar os objetos de todos os chunks seguintes:

let headers = null;

function processChunk(text) {
  const lines = text.split('\n');
  if (!headers) {
    headers = lines.shift().split(',');
  }
  for (const line of lines) {
    if (!line.trim()) continue;
    const values = line.split(',');
    result.push(Object.fromEntries(headers.map((h, i) => [h, values[i]])));
  }
}

Atenção: este parser simples não lida com campos que contêm vírgulas entre aspas. Para CSVs com esse padrão, use uma biblioteca como papaparse, que tem suporte nativo a streaming e Web Workers.

O CSV para JSON do Quick Tools

O conversor usa exatamente essa abordagem: chunking + processamento assíncrono, com progresso visual. Para arquivos acima de 10MB, ele automaticamente move o parsing para um Worker. O resultado é exportável como JSON formatado ou minificado.

Para dados financeiros sensíveis que você não quer enviar para um servidor, essa abordagem client-side é a única opção correta.

Como decidir entre converter tudo ou processar em stream

A diferença prática entre uma conversão simples e uma conversão em stream aparece quando o arquivo deixa de caber confortavelmente na memória. Para arquivos pequenos, converter CSV para JSON de uma vez é mais simples e suficiente. Para arquivos grandes, o ideal é ler linha por linha, validar cada registro e escrever a saída progressivamente.

Use processamento em stream quando o CSV vem de exportações operacionais, relatórios financeiros, logs ou integrações com milhares de linhas. Esse modelo permite detectar erros cedo, exibir progresso e evitar travar o navegador ou o processo Node. Também facilita descartar linhas inválidas sem perder o arquivo inteiro.

Checklist de validação

Antes de confiar no JSON final, confira encoding, delimitador, cabeçalhos duplicados, colunas vazias e quebras de linha dentro de aspas. Esses são os casos que mais quebram parsers ingênuos. Depois, valide tipos: números como string, datas em formatos mistos e valores booleanos escritos como sim, não, true, false, 1 ou 0.

Para arquivos pequenos, o CSV to JSON resolve rapidamente a inspeção visual. Para pipelines recorrentes, use a ferramenta para entender o formato e depois replique a regra em código com testes cobrindo linhas problemáticas.

HT
Autor
Hugo Tanaka
Japonês-brasileiro de segunda geração, cresceu vendo o pai debugar planilhas de logística em BASIC. Desenvolvedor full-stack com foco em tooling e DX — o papel que finalmente uniu código, escrita e obsessão por produtividade num lugar só. Escreve para quem já sabe programar e quer resolver um problema agora.
Ver perfil