Perfilado de código TypeScript: encontrando cuellos de botella en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Perfilado de código TypeScript: encontrando cuellos de botella en la práctica



Cuando su proyecto TypeScript comienza a ralentizarse y los usuarios se quejan de retrasos, llega el momento del perfilado. El perfilado no es solo "mirar qué es lento", sino un enfoque sistemático para identificar cuellos de botella en el rendimiento del código. En este artículo, analizaremos métodos prácticos de perfilado de código TypeScript con ejemplos y herramientas reales.



¿Por qué perfilar código TypeScript?



TypeScript se compila a JavaScript, y todos los problemas de rendimiento inherentes a JS se trasladan a TS. Sin embargo, TypeScript añade sus propios matices: la tipificación, los decoradores y los genéricos pueden crear gastos generales inesperados. El perfilado ayuda a responder preguntas como:

  • ¿Qué función se ejecuta durante más tiempo?
  • ¿Dónde se produce una fuga de memoria?
  • ¿Por qué la animación se ralentiza a 60fps?
  • ¿Qué algoritmo necesita optimización?


Herramientas para perfilar TypeScript



Chrome DevTools (para código de navegador)

La herramienta más potente para el frontend. Abra la pestaña Performance, presione Record, realice la acción y detenga la grabación. Verá un flamegraph: una visualización de las llamadas a funciones y su tiempo de ejecución.



// Ejemplo de código lento para perfilarfunction heavyCalculation(iterations: number): number {    let result = 0;    for (let i = 0; i < iterations; i++) {        result += Math.sqrt(i) * Math.sin(i);    }    return result;}

// Ejecútelo en la consola del navegador, luego perfíleloheavyCalculation(1000000);


Node.js — perfilador integrado

Para código de servidor, use el flag --inspect y Chrome DevTools, o el integrado --prof para generar registros.



// server.tsimport express from 'express';

const app = express();

app.get('/heavy', (req, res) => { const data = processData(10000); res.json({ result: data });});

function processData(size: number): number[] { const arr: number[] = []; for (let i = 0; i < size; i++) { arr.push(i * Math.random()); } return arr.sort((a, b) => a - b);}

app.listen(3000);// Ejecución: node --prof dist/server.js


Benchmark.js para mediciones precisas

Cuando necesite comparar dos implementaciones, use la librería benchmark.



import Benchmark from 'benchmark';

const suite = new Benchmark.Suite();

// Variante lentafunction slowSearch(arr: number[], target: number): boolean { for (let i = 0; i < arr.length; i++) { if (arr[i] === target) return true; } return false;}

// Variante rápida con Setfunction fastSearch(arr: number[], target: number): boolean { const set = new Set(arr); return set.has(target);}

const testArray = Array.from({ length: 10000 }, (_, i) => i);

suite .add('slowSearch', () => slowSearch(testArray, 9999)) .add('fastSearch', () => fastSearch(testArray, 9999)) .on('cycle', (event: any) => console.log(String(event.target))) .on('complete', function(this: any) { console.log('Fastest is ' + this.filter('fastest').map('name')); }) .run({ async: true });


Ejemplos prácticos de búsqueda de cuellos de botella



Ejemplo 1: Fuga de memoria mediante closures

Un problema típico en aplicaciones React son los closures que retienen referencias a objetos grandes.



// Código problemáticofunction createHeavyComponent() {    const hugeData = new Array(1000000).fill('data');        return {        getData: () => hugeData, // el closure retiene hugeData        updateData: (newData: string) => {            // mutación, pero la referencia permanece            hugeData.push(newData);        }    };}

const component = createHeavyComponent();// hugeData no será recolectado por el GC mientras exista component


<

Blogs

Book Recommendations