TypeScript на максималках: как ускорить код в 10 раз

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Ваш TypeScript-код работает медленно? Пора заглянуть под капот

Вы написали идеальный код на TypeScript. Типы проставлены, абстракции красивые, тесты зелёные. Но продакшен-сервер «тормозит», а React-компоненты перерисовываются с задержкой. Знакомо? Часто проблема не в логике, а в производительности TypeScript, которую мы не замечаем до момента, когда нагрузка становится реальной.

В этой статье мы не будем говорить о скорости компиляции — это тема для отдельного разговора. Мы сфокусируемся на runtime-производительности: как профилировать готовый код, находить «бутылочные горлышки» и оптимизировать TypeScript так, чтобы приложение летало. Вы узнаете, почему map в 10 раз быстрее forEach, как GC убивает FPS и какие инструменты для профилирования стоит носить с собой.

Инструменты профилирования TypeScript: от Chrome до Node.js

Прежде чем что-то оптимизировать, нужно понять, где именно теряются миллисекунды. Для этого в TypeScript существует три основных подхода к профилированию.

1. Chrome DevTools Performance Tab

Если вы пишете фронтенд, ваш лучший друг — вкладка Performance в Chrome DevTools. Запись профиля покажет вам полную картину: какой JavaScript выполняется дольше всего, сколько времени занимает сборка мусора, и где происходят «просадки» FPS. TypeScript после компиляции — это чистый JavaScript, поэтому профилировщик видит именно то, что выполняется.

// Пример: профилируем "тяжелый" расчет в браузере
function processLargeArray(items: number[]): number[] {
  const result: number[] = [];
  for (let i = 0; i < items.length; i++) {
    // Симуляция тяжелой работы
    result.push(items[i] * Math.sqrt(items[i]));
  }
  return result;
}

console.time('processLargeArray');
const data = Array.from({ length: 100000 }, (_, i) => i);
processLargeArray(data);
console.timeEnd('processLargeArray');

Откройте Performance Tab, нажмите Record, выполните этот код — и вы увидите точное время выполнения, а также стек вызовов. Если функция занимает более 100ms, это повод задуматься об оптимизации TypeScript-кода.

2. Node.js Profiler (--prof и --inspect)

Для бэкенда на Node.js с TypeScript используйте встроенный профайлер. Запустите приложение с флагом --prof:

node --prof dist/server.js

После завершения работы создается файл isolate-*.log. Преобразуйте его в читаемый вид:

node --prof-process isolate-*.log > processed.txt

В файле вы увидите, какие функции (в том числе из скомпилированного TypeScript) потребляют больше всего CPU. Это незаменимый инструмент для профилирования TypeScript в продакшене.

3. V8 CPU Profiler через Clinic.js

Для более наглядного анализа используйте Clinic.js. Он рисует красивые флейм-чарты и показывает, где TypeScript-код «тормозит».

npm install -g clinic
clinic doctor -- node dist/server.js

После тестирования откройте HTML-отчет — вы увидите, какие функции занимают 90% времени. Часто это неожиданные места: например, частые вызовы JSON.parse или неоптимизированные циклы.

Топ-5 техник оптимизации TypeScript-кода

Когда профилировщик показал «горячие точки», пора браться за оптимизацию. Вот пять проверенных способов ускорить TypeScript, которые я использую в своих проектах.

1. Избегайте map, если нужен forEach

Звучит странно, но map создает новый массив, даже если вы его не используете. Если вам нужно только выполнить действие, используйте forEach или классический for.

// Медленно — создает ненужный массив
const ids = users.map(user => {
  sendEmail(user.email);
  return user.id;
});

// Быстро — просто итерация
for (const user of users) {
  sendEmail(user.email);
}

Бенчмарк показывает, что for...of работает в 2-3 раза быстрее map на массивах от 10 000 элементов. Это критично для производительности TypeScript в циклах.

2. Убирайте лишние копии объектов

Spread-оператор и Object.assign создают поверхностные копии. Если вы делаете это в горячем цикле, вы убиваете производительность и нагружаете GC.

// Плохо — копия на каждую итерацию
const updatedUsers = users.map(user => ({
  ...user,
  lastLogin: new Date()
}));

// Хорошо — мутируем, если это допустимо
for (const user of users) {
  user.lastLogin = new Date();
}

Если мутация недопустима, создавайте новый объект, но не внутри цикла — вынесите логику в отдельную функцию, которая будет вызываться по необходимости.

3. Оптимизируйте работу с массивами: Set вместо includes

Проверка вхождения элемента в массив через includes имеет сложность O(n). Если вы делаете это много раз, используйте Set — сложность O(1).

// Медленно — O(n) на каждую проверку
const blacklist = ['user1', 'user2', 'user3'];
if (blacklist.includes(username)) {
  throw new Error('Blocked');
}

// Быстро — O(1)
const blacklistSet = new Set(['user1', 'user2', 'user3']);
if (blacklistSet.has(username)) {
  throw new Error('Blocked');
}

На массиве из 10 000 элементов разница в скорости — в 1000 раз. Это одна из самых простых и эффективных оптимизаций TypeScript.

4. Дебаунс и троттлинг для событий

Если ваш TypeScript-код обрабатывает события (scroll, resize, input), не делайте это на каждый чих. Используйте дебаунс или троттлинг.

// Без оптимизации — дергается на каждое нажатие
input.addEventListener('input', (e) => {
  const value = (e.target as HTMLInputElement).value;
  fetchSuggestions(value); // Дорогой запрос
});

// С дебаунсом — ждем 300ms после последнего ввода
function debounce<T extends (...args: any[]) => any>(fn: T, delay: number) {
  let timer: ReturnType<typeof setTimeout>;
  return (...args: Parameters<T>) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

const handleInput = debounce((e: Event) => {
  const value = (e.target as HTMLInputElement).value;
  fetchSuggestions(value);
}, 300);

input.addEventListener('input', handleInput);

Это снижает количество вызовов функций с тысяч до десятков, что радикально улуч

Блоги

Рекомендаций по книгам