Node.JS [ru] | Серверный JavaScript
11.2K subscribers
170 photos
7 videos
25 files
3.58K links
Node.js, backend и AI-разработка: статьи, новости, вайбкодинг, автоматизация и работа с ИИ-агентами.

Личный блог автора - @just_genych
По вопросам рекламы или разработки: @g_abashkin

РКН: https://vk.cc/cJPGOP
Download Telegram
Anthropic раскатал схему работы Fable 5 в обнимку с Sonnet 5 — тут два варианта

Первый вариант — Fable 5 втыкается как «советник» (Advisor). Sonnet 5 тащит задачу, но периодически дёргает Fable 5 за стратегическим советом. На тесте SWE-bench Pro такая связка вывозит примерно 92% от качества Fable 5, при этом платишь всего 63% от её цены. Fable 5 дёргают примерно раз на задачу. Подробнее в документации.

Второй расклад — Fable 5 работает оркестратором. Она разруливает план и раздаёт таски исполнителям — Sonnet 5. В Benchmark-тестах BrowseComp на Claude Managed Agents такая конфигурация показала 96% производительности Fable 5, а стоила 46% от оригинала. Жирные по ресурсам задачи скидывают на Sonnet 5. Пример в кукбуке.

Claude Managed Agents переваривает оба подхода (документация). Каждый подагент держит свой кэш, так что при повторных вызовах не придётся платить за полную пережевку контекста.

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🤣 Мы все ждали когда это начнётся

✖️ xCode Journal
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4
Системный аналитик — не просто почтальон между бизнесом и разрабами. Часто тащит на себе интегратора, деливери-менеджера, продакта, архитектора и даже скрам-мастера. И периодически в него летят таски, которые вообще не его профиль. Это такой челлендж: либо ты закаляешься, либо ловишь ментальный аут.

Это уже второй заход от Александра Малышева, лид-аналитика из МТС Cashback. И тут он расписывает зону ответственности SA. Всё в стихах и с юмором — прямо как народная сказка.

📖 Читать сказку

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1
Anthropic решила, что пора поживиться, и попыталась снять с парня $16,6 млн просто за красивые глаза 👻

Корейский юзер, у которого бесплатный тариф и ноль запросов к API, получил официальную бумажку с требованием оплатить $16,6 млн. А за день до этого ему же прилетел запрос на $1,6 млн — сумма за ночь выросла в 10 раз. Хорошо, что банк просто зарубил эти попытки из-за лимита карты.

Anthropic пока молчит. И это не единичный случай: на Reddit народ тоже жалуется на внезапные списания от этой конторы.

Инфа сотка 😁

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Неявная блокировка Event Loop: как MapIterator убивает производительность в hot-path

Казалось бы, обычный for...of по Map — и вдруг Event Loop начинает тормозить. Проблема в скрытой аллокации MapIterator при деоптимизации V8. В hot-path это приводит к частому GC и блокировкам.

Почему это происходит
V8 в оптимизированном коде (TurboFan) может не аллоцировать итератор — он сохраняется на стеке или убирается escape analysis. Но деоптимизация из-за полиморфизма типов ключей (строки и числа), try/catch внутри цикла или превышения inline-лимитов заставляет создавать MapIterator в куче. В production это вызывает пинг-понг с GC.

Диагностика на практике
- --trace-gc — ищем аллокации MapIterator.
- --trace-deopt — смотрим причину: часто смешение типов ключей или нестабильный полиморфизм.
- Сравни for...of, map.forEach и ручной обход через Array.from(map.keys()) в бенчмарке. Разница может быть кратной.

Практический совет
В hot-path используй forEach, а не for...of. V8 может встроить его колбэк и избежать аллокации итератора. Если нужны ключи — закешируй их через Array.from и обходи обычным циклом.

Типичная ошибка
Не проверяешь стабильность типов ключей Map. Если ключи смешанные (строки и числа) — for...of гарантированно деоптимизируется. Зафиксируй типы или используй forEach.

Вывод: Аллокация MapIterator в hot-path из-за деоптимизации V8 — скрытая причина лагов Event Loop; замена for...of на map.forEach или кеширование ключей через Array.from устраняет проблему без ущерба для читаемости.
2
Заглянули под капот ChatGPT

Парень, который копался в производительности Linear, потратил несколько дней на изучение сорцов, бандлов и запросов к ChatGPT. Внутри — React Router 7, TanStack Query, Radix и ProseMirror. Вся ненужная хрень грузится только когда юзер начинает долбить по клавишам.

Base UI теперь рулит в shadcn/ui по умолчанию — свежие проекты стартуют на Base UI, а не на Radix. Radix пока не выкинули на помойку, оба набора компонентов доступны. Но для нового говна рекомендуют Base UI.

Shadcn подвезли переводы без передеплоя — облачный бэкенд от команды i18next с функциями saveMissing, редактированием в контексте, AI-переводом и мгновенными апдейтами через CDN. Есть бесплатный тариф, делают в Швейцарии.

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
К 2013 году американская журналистика уже пятый год лежала на лопатках. Кризис 2008-го вынес рекламную модель прессы: в газетных ньюсрумах США осталось меньше половины сотрудников, десятки тысяч спецов остались не у дел. Потерявшие работу журналисты ушли на фриланс. Параллельно с этим университетские программы по научной журналистике (MIT, Нью-Йоркский, Санта-Круз) стабильно штамповали новых выпускников. И третий поток — учёные, свалившие из академии (постдоки, не получившие должность).

Итог: три потока продавцов и дохлый ручеёк покупателей. У Science или Smithsonian — 10-20 заказов на фриланс в месяц, заявок — десятки в день.

Источник: Хабр

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
structuredClone и Error с глубоким стек-трейсом: неявный убийца производительности в worker_threads

Передаёте Error через worker.postMessage()? Если стек-трейс глубокий — после цепочки асинхронных вызовов — V8 может незаметно блокировать поток на сериализации. Производительность падает линейно, а вы ищете причину в другом месте.

Почему это происходит

При вызове structuredClone V8 сериализует все перечислимые свойства объекта, включая .stack. Для Error с сотнями фреймов (длинные URL, аргументы функций) V8 парсит стековую строку целиком. Каждый фрейм проверяется, разбирается — и это происходит синхронно в вызывающем потоке. Пример: 5000 повторений .stack через repeat дают задержку ~100ms на postMessage.

Как диагностировать

Используйте --trace-event-categories или clinic flame. Ищите пики CPU в structuredClone. Сравните время postMessage с простым объектом против Error — разница в 10-50 раз при глубоком стеке. Типичная ошибка: разработчики грешат на дорогие вычисления, а на самом деле V8 тупо сериализует строчку.

Решение: не передавайте полный Error

Клонируйте только критичные поля: message, code, line, fileName. Для огромных стеков передавайте идентификатор ошибки, а полный стек собирайте локально. Можно упаковать Error в простой объект:

const safeError = {
message: err.message,
code: err.code,
line: err.stack?.split('\n')[1]
};
worker.postMessage(safeError);


Production-кес: в нашем сервисе 20% CPU уходило на structuredClone ошибки с 1500+ фреймами. После замены на { msg: err.message } блокировка исчезла полностью.

Вывод: Не передавайте полный Error между воркерами при глубоких стеках — сериализация через structuredClone может незаметно съедать 10-20% CPU и блокировать поток.
👍1
Reverse Engineering ChatGPT Web — чувак, который когда-то разбирал Linear по косточкам, решил не останавливаться и вдумчиво покопался в исходниках ChatGPT. Он прошерстил бандлы, запросы и нарыл там React Router 7, TanStack Query, Radix и ProseMirror. Фишка в том, что весь ненужный хлам не грузится, пока ты не начнешь стучать по клавиатуре.

Base UI теперь рулит в shadcn/ui — новые проекты на shadcn/ui едут на Base UI, а не на Radix. Радикс не умер, компоненты доступны для обеих платформ, но для свежих проектов советуют именно Base UI.

TypeScript 7.0 — выкатили компилятор на Go, который шпарит в 10 раз быстрее. Правда, без нормального API от версии 6.0 пока что его рекомендуют кучке фронтенд-фреймворков.

Vercel пригрела команду Better Auth — той самой популярной либы для аутентификации.

React Navigation 8.0 — ребята делятся успехами, в том числе навигацией с поддержкой Suspense.

Next.js — опубликовали официальный RFC для WebSocket в Route Handlers.

npm v12 — теперь жизненные циклы скриптов и сборки node-gyp по умолчанию не запускаются.

Подробнее — в выпуске React Status #482.

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
1
TypeScript 7 переписали на Go: разбираемся, правда ли он в десять раз шустрее

📣 Главная цифра из блога TypeScript: проверка типов в проекте VS Code (примерно 1,5 млн строк) упала с 77,8 с до 7,5 с. Отсюда и заголовок — «примерно в 10 раз быстрее».

Это не обзор релиза, а попытка повторить один график на монорепе, специально склеенном для теста. Два компилятора на одной тачке, все цифры на руках, плюс репозиторий, где любой результат можно дёрнуть командой pnpm bench. Спойлер: TS7 реально быстрее, и отрыв чувствуется. Но «в десять раз» — это для одного конкретного кейса, в других сценариях магия улетучивается.

Суть вот в чём: «10×» — это про проверку типов на большом проекте, а не про всё подряд. TS7 реально ускоряет валидацию и жрёт меньше памяти, бенчи это подтверждают. Но в 7.0 нет стабильного программного API — из сборки вылетели кастомные трансформеры, плагины к tsserver и типизированный линтинг. Так что вопрос миграции не «быстрее или нет», а «живёте ли вы без этого API».

🔗 Читать далее

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Диагностика и устранение неявного замедления TLS-рукопожатий из-за скрытой конкуренции за entropy pool в кластеризованных HTTPS-серверах

Если вы держите Node.js в кластере — через PM2 или встроенный cluster, — могли замечать странные задержки при HTTPS-соединениях. Вроде всё настроено, а рукопожатия то 5 мс, то 500+. Одна из неочевидных причин — драка за entropy pool.

Причина
Внутри каждого TLS-рукопожатия Node.js дёргает случайные числа для ключей. В Linux это /dev/urandom или getrandom(). Когда несколько воркеров одновременно лезут в один пул энтропии, начинаются блокировки. Особенно в контейнерах без аппаратного RNG — там стекло быстро заканчивается.

Симптомы: время рукопожатия плавает хаотично, иногда blocked for more than 120 seconds. strace покажет, что провал в crypto.randomFill().

Диагностика
Берите strace -e trace=getrandom -p <PID> -o entropy.log. Если вызовы висят дольше 1 мс — проблема. Проверьте скорость энтропии: dd if=/dev/urandom bs=1024 count=100 | pv.

Решения
* Отдельный seed для каждого воркера. При старте слать его через IPC из master:
process.on('message', (msg) => {
if (msg.type === 'seed') {
global._seed = msg.seed;
}
});

* Для операций после старта — только асинхронный crypto.randomFill с callback. Синхронный вызов дёргает блокировку пула.
* На bare-metal поставьте haveged или rng-tools, в облаке — virtio-rng.

Типичная ошибка
Не используйте Math.random() для криптографии — это антипаттерн, который не решает проблему, а только создаёт уязвимости.

Вывод: Диагностика через strace и управление seed-ами — эффективный способ ускорить TLS без переписывания стека, но критично проверить нагрузку на entropy pool в кластере с 10+ воркерами.
👾 Тамагочи из 90-х: собираем на коленке на JavaScript

Автор честно признаётся: раньше он вообще не втыкал, что это за зверь. Ну, видел в американском кино, типа в «Менталисте», где герой чуть ли не со слезой вспоминает виртуального питомца и даже толкает его коллеге. А потом до него дошло: если эта игрушка пережила три десятилетия и кучу раз её перепридумывали — значит, там что-то серьёзное, а не просто мусор.

Так он решил врубиться, что это за хрень и как она работает, и начал с истории. Без неё объяснять старые штуки — пустая трата времени.

Дальше на Habr

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
2🐳2
Скрытая утечка памяти: когда WeakRef и Symbol.dispose убивают DI-контейнер

В long-lived DI-контейнерах циклические зависимости в сочетании с WeakRef и Symbol.dispose создают неочевидную проблему: коллбэки очистки замыкают целые графы объектов, превращая WeakRef в бессмысленный инструмент. Разработчики часто доверяют GC, не замечая, что память не освобождается годами.

Как возникает теневая связность
Когда вы регистрируете коллбэк в WeakMap на основе WeakRef, замыкание захватывает dispose-функцию, которая тянет весь service-граф. Даже если WeakRef.deref() возвращает undefined, ссылка в замыкании удерживает объекты. Они становятся "полуживыми" - не имеют сильных ссылок, но GC их не собирает из-за скрытой цепочки через dispose.

Диагностика в production
Запуск с --expose-gc и global.gc() не покажет освобождения. Heap snapshot в Chrome DevTools обнаружит объекты без явных strong references, но присутствующие в WeakMap. Это сигнал, что проблема в замыканиях коллбэков. Типичная ошибка: проверка только первого уровня графа.

Решение 1: точечное замыкание
Вместо передачи всего service в коллбэк берите только метод через bind:
const handler = service[Symbol.dispose]?.bind(service);

Это разрывает неявную связь с полным графом.

Решение 2: FinalizationRegistry
Он не удерживает ссылку на объект. Регистрируете коллбэк с heldValue, который не ссылается на service:
const registry = new FinalizationRegistry((heldValue) => {});
registry.register(service, cleanupToken, token);


Решение 3: отказ от WeakRef при циклах
Для циклических зависимостей используйте reference counting в пуле синглтонов. Надёжнее, хоть и менее элегантно:
class RefCountPool {
private refs = new Map();
acquire(key) { this.refs.set(key, (this.refs.get(key) || 0) + 1); }
release(key) { if (this.refs.get(key) === 1) this.refs.delete(key); }
}


Вывод: WeakRef не гарантирует безопасной очистки при наличии замыканий в коллбэках, поэтому всегда профилируйте память в циклах зависимости и используйте FinalizationRegistry или reference counting для long-lived контейнеров.
Redux с React так и не подружился

Без обид, но тупо взять Redux и воткнуть его в React не выйдет. Придётся тащить за собой ещё и «react-redux». Тогда зачем эти сказки, что «Redux works with any UI layer»?

Разбираемся: https://habr.com/ru/articles/1058110/

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
😁2
Неявный рассинхрон состояния при AsyncLocalSnapshot, EventEmitter и Symbol.asyncDispose

Работаете с распределёнными очередями задач? Тогда наверняка сталкивались с AsyncLocalStorage для проброса контекста. Но связка AsyncLocalSnapshot с EventEmitter и забытый Symbol.asyncDispose приводят к багу, который воспроизводится раз на 50 запусков — контекст устаревает, состояние утекает.

Почему контекст утекает
AsyncLocalSnapshot замораживает контекст при создании, но колбэк от EventEmitter может жить дольше задачи. Если слушатель не удалён, он выполняется с устаревшим состоянием. В production это даёт stale data — задача обрабатывается с контекстом предыдущей или undefined.

Production-пример ошибки
Типичный сценарий: воркер запускает задачу, подписывается на события прогресса через emitter.on, но не чистит слушатель. В итоге в следующей задаче AsyncLocalSnapshot возвращает старый контекст. Код:
const snapshot = new AsyncLocalSnapshot(als);
emitter.on('event', snapshot.run(data => {
console.log(als.getStore()); // устаревший контекст
}));
// Слушатель не удалён — баг


Типичная ошибка
Забывают реализовать Symbol.asyncDispose для временных слушателей. Или создают снапшот вне обработчика, вместо того чтобы делать это внутри. Совет: всегда используйте try/finally для очистки подписок.

Практический совет
Для долгоживущих слушателей не используйте AsyncLocalSnapshot — сохраняйте контекст в замыкании. Если нужно, чистите через finally или Symbol.asyncDispose:
class Worker {
async [Symbol.asyncDispose]() {
emitter.removeAllListeners('progress');
}
}


Вывод: Управляйте временем жизни подписок явно — AsyncLocalSnapshot это моментальный снимок, а не долгоживущий контекст.
This media is not supported in your browser
VIEW IN TELEGRAM
Виртуальные Scroll-контейнеры

Йо, народ. Сегодня заценим инструмент ng-virtual-scroll-view. В прошлый раз я раскатывал про универсальные виртуализированные списки, которые внутри юзали одноосевой виртуальный scroll-контейнер. Решил из проекта ng-virtual-list выковать еще одну штуку — двухосевой виртуальный scroll-контейнер ng-virtual-scroll-view. Поддерживает Angular с 14 по 22 версии. API и примеры использования — в документации. Читай дальше

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
npm 12, TypeScript 7.0 и Bun на Rust

Выкатили npm 12 — install-скрипты теперь выключены по дефолту. Сломов дофига, так что сперва лучше проапгрейдиться до 11.18.0. GitHub

Финальный TypeScript 7.0 — на Go и «в 10 раз быстрее». Но полный API пока не докрутили, поэтому многие советуют пока не слезать с 6.0.

Bun переехал с Zig на Rust — автор выкатил полный репортаж о том, как портировал рантайм. Кучу инстансов Claude Code припахали, суммарно сожгли ~$165k по API-ценам. Rust-версия станет базой для Bun 1.4, его ждут с часу на час. Jarred Sumner

Node.js 26.5.0 — заимпортили текстовые файлы в ES-модулях через import attributes и blob.textStream().

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3👍2
Неявное зависание Promise.all при отмене AsyncIterator через AbortController

Вы используете for await...of с асинхронным генератором и AbortController для отмены. Кажется, всё чисто, но Promise.all зависает намертво. Проблема в том, что вызов abort() вызывает return() генератора, но если внутри остался незавершённый промис (таймер, подписка, поток), он просто висит, и Promise.all никогда не завершится.

Как возникает утечка
Когда abort() срабатывает внутри for await...of, итератор завершается. Но если в генераторе есть запущенный, но не завершённый setInterval, await на потоке данных или подписка на событие, этот промис остаётся висеть в памяти. Например, генератор каждую секунду отправляет данные, а при abort обработчик завершает итерацию, но не очищает таймер. Promise.all ждёт этот таймер вечно.

Диагностика на практике
Добавьте в конец return() генератора console.log('return called'). Если return вызывается, а Promise.all не завершается — ищите, какой ресурс утекает. Используйте обёртку с таймаутом: Promise.race([Promise.all(...), AbortSignal.timeout(5000)]). В продакшне это спасёт от вечного ожидания, но не решит корень проблемы.

Совет по исправлению
Всегда оборачивайте тело асинхронного генератора в try/finally. В finally явно очищайте все ресурсы: удаляйте слушатели, отменяйте таймеры, разрешайте ожидающие промисы. Например, если внутри генератора есть setInterval:
async function* gen(signal) {
const timer = setInterval(() => {}, 1000);
try {
while (!signal.aborted) {
await new Promise(r => setTimeout(r, 100));
yield data;
}
} finally {
clearInterval(timer);
}
}


Вывод: Каждый yield и await в асинхронном генераторе должен быть гарантированно завершён до конца итерации, иначе return() не прервёт внутренние промисы, что приведёт к невосстанавливаемому зависанию.
1
MinIO, MongoDB, PostgreSQL для хранения 25 лет истории стоимости акций

💾 Когда ты строишь эмулятор для проверки торговой стратегии — 20 акций, 25 лет поминутных данных — выбор хранилища превращается в головную боль архитектурного уровня.

Автор раскурил, почему MinIO тут не взлетел, где MongoDB уперлась в потолок, и как PostgreSQL с Pgpool-II и read-репликами срезал время чтения свечи с 40мс до 10мс.

Читать далее: https://habr.com/ru/articles/1059062/

👉 Node.JS [ru]
Please open Telegram to view this post
VIEW IN TELEGRAM
Как получить оффер в Яндекс, Сбер, МТС и другие крутые компании?

На фото ребята из моего комьюнити, где уже больше 220 frontend-разработчиков. Все они успешно устроились в крутые компании и получили офферы от 300 тыс рублей 🫂

👋 Привет, меня зовут Тихон, я действующий Frontend-разработчик и ментор. За руку довожу до оффера в Big Tech и остаюсь рядом на испытательном сроке.

В их жизни больше нет бесконечных скучных созвонов, безуспешных откликов на вакансии, странноватых собесов с вопросами словно ты на олимпиаде.


И у тебя тоже получится 😎

У меня есть канал, где я:
👉 Показываю, как пройти HR-фильтр и превратить отклики в реальные приглашения
👉 Помогаю найти мотивацию и разбираюсь с убеждениями, которые мешают расти
👉 На примерах показываю, как проходить собеседования, включая техничку
👉 Разбираю резюме и делюсь лайфхаками — например, как аккуратно «пинговать» рекрутеров

И регулярно выкладываю полезное:
▪️ Задачи, на которых валятся кандидаты
▪️ Подборка из 100+ каналов с вакансиями для разработчиков
▪️ 100 вопросов, которые помогут тебе на собеседовании
▪️ Чек-лист для проверки своего резюме

Подписывайся: https://t.me/+KcX6eD0fuRY3M2Uy

Реклама, erid: 2W5zFJKcvZP ИП Галактионов Тихон Витальевич, ИНН 771618975809