TGViewer
Channel Public Channel
Настоящий JavaScript

Настоящий JavaScript

@true_js

Тот самый канал по JavaScript.

Личный блог автора - @just_genych
По вопросам рекламы или разработки: @g_abashkin
Subscribers
5.89K
Photos
3K
Videos
8
Links
2.7K

Showing posts older than #3690 · Back to latest

Older Posts 20 shown
Post #3688 592
😎 Anthropic выпустила официальный гайд по работе с новенькой Claude Opus 5

Главный совет — перестаньте микроменеджить модель. Opus 5 лучше работает, если просто дать ей полное ТЗ и не просить лишний раз перепроверять себя.

Ещё один нюанс: если хотите короткие ответы, теперь это нужно писать явно, так как по умолчанию модель стала гораздо многословнее.

✖️ xCode Journal
Post #3686 535
🤯 Автор «Чистого кода» больше не читает код, написанный ИИ-агентами

73-летний Дядя Боб признался, что теперь вообще не проверяет код. Вместо этого он обкладывает агентов юнит-тестами, QA, метриками качества и жёсткими ограничениями. И если вайбкод прошёл всю эту систему проверок, то и читать его необязательно.

«Это единственный способ, которым я могу воспользоваться их продуктивностью.»


✖️ xCode Journal
Post #3684 426
⁣Неявные баги в Promise.withResolvers() при передаче управления между модулями в ESM-циклах и динамических импортах

Этот баг пропускают и TypeScript, и линтер — вы узнаете о нём только на проде. Promise.withResolvers() (ES2024) в ESM-циклах создаёт состояние гонки, когда resolve/reject экспортируются из модуля, участвующего в циклических зависимостях.

Как работает гонка

В ESM модули выполняются синхронно при импорте. Если модуль A экспортирует resolve, а модуль B вызывает его на этапе инициализации, resolve может быть undefined или ссылка на него может быть перезаписана после вызова. Пример:
// module-a.ts
const { promise, resolve } = Promise.withResolvers<void>();
export { promise, resolve };

// module-b.ts
import { resolve } from './module-a';
resolve(); // Вызов до завершения module-a


Проблема с динамическим импортом

Динамический импорт добавляет ещё один слой неопределённости. Промис может быть уже разрешён до момента, когда импорт завершится:
// module-c.ts
const { promise, resolve } = Promise.withResolvers();
export default promise;
export { resolve };

// вызов
const module = await import('./module-c');
module.resolve('value'); // Промис уже был разрешён — вызов игнорируется


Типичные ошибки и решения

* Не экспортируйте resolve/reject из модуля, который участвует в циклических зависимостях — это гарантирует частичное выполнение модуля и некорректные ссылки.
* При динамическом импорте устанавливайте тайм-аут для промиса с Promise.race(), чтобы не зависнуть навсегда.
* Для сложной синхронизации между модулями используйте EventEmitter или очереди — они явно управляют порядком выполнения.

Бонусная ловушка

resolve/reject — обычные функции, их можно вызывать сколько угодно раз. В ESM-циклах повторный вызов просто игнорируется, но вы не заметите этого на тестах. На проде — вечно висящий промис или пропущенный reject.

Чек-лист для production:
- Promise.withResolvers() — только внутри модуля, никогда не экспортируя resolve или reject наружу.
- Никаких асинхронных вызовов на верхнем уровне модуля, если экспортируете resolve.
- Если архитектура требует внешнего управления — используйте AbortController для отмены.

Вывод: Promise.withResolvers() безопасен только в изолированном контексте; экспорт resolve/reject в ESM-циклах превращает код в недетерминированную гонку, которую невозможно отловить статическим анализом.
Post #3683 369
Разбираем Next.js по косточкам

Чувак выкатил свой опыт по настройке проекта на Next.js.
На примере реального приложения разжевал: структуру папок, маршруты, общение с данными через DAL, авторизацию, проверки, тесты и прочие подходы, которые он юзал во время разработки.

Никакой “это истина в последней инстанции”. Просто один из вариантов, как можно наваять нормальную организацию.

Читать далее

👉 JS
Post #3681 397
Ленивая подгрузка — не таблетка от всего

Напихал ленивых модулей в Angular, включил прод-сборку — а твой main.js всё ещё весит почти 2 МБ. Знакомо?

Чаще всего проблема таится в общих модулях, жирных зависимостях и импортах, которые тупо не дают tree-shaking’у сделать свою работу. В статье разбирают, как выкурить мусор из бандла и реально убить время загрузки.

Читать далее

👉 JS
  • 👍 1
Post #3680 421
🥲 Зарплаты айтишников растут медленнее инфляции

Это показало новое исследование на 45+ тысяч зарплат специалистов. Изучаем главное, чтобы быть готовыми к рынку:
- Медианная зарплата в IT в первой половине 2026 года составила 191 000 ₽ — это всего на 4% больше, чем полгода назад. При этом прогнозируемая годовая инфляция — 4,5–5,5%.

- Самый щедрый по офферам город, разумеется, Москва. Там медиана по зп — 235 тысяч, в регионах же всего 160.

- Топ-5 самых высокооплачиваемых специальностей в IT: на первом месте — разработчики, дальше идут менеджеры, администраторы, специалисты по информационной безопасности и аналитики.

- Самые высокие зарплаты среди языков при этом у Objective-C — этим гигачадам предлагают 400 000 ₽. Следом идут Elixir (348к), Swift и Golang с 326 и 325 тысячами рублей.


✖️ xCode Journal
Post #3679 467
WebStorm 2026.2: TypeScript 7, GitHub Copilot и ИИ-агенты

Да, в России с ним теперь не всё гладко — но WebStorm всё ещё рулит как среда для веб-девелоперов. Выкатили новую версию 2026.2: там завезли поддержку TypeScript 7, встроили нативно GitHub Copilot и добавили менеджер скиллов для ИИ-агентов.

React, Vue, Svelte, Angular — всё подтянули. Отладка, работа с Node.js и Git стали шустрее, сама IDE — стабильнее. В статье разбирают все свежие плюшки, а ещё — что там по OpenIDE и переходу на платформу 2026.2.

Читать далее

👉 JS
Post #3677 427
Transferum — легковесная тула на TypeScript, которая помогает собирать реактивные графы для растаскивания и обработки данных.

Ноды в этом графе друг друга не видят, а связи между ними натягиваются автоматически — по тому, что каждая из них умеет. Ещё тут есть вычислимые типы, которые контракты проверяют на этапе компиляции, и маршрутизация данных без лишнего геморроя.

В статье разбирают, как это работает, и показывают примеры построения динамических пайплайнов для IoT-датчиков и панелей управления.

Читать далее

👉 JS
Post #3673 433
История корутин: как они появились, выстрелили, угасли и вернулись

Привет, Хабр. Я Дмитрий Попов, делаю Android в ПСБ. В один прекрасный момент до меня дошло: нихера я не шарю, что такое корутина и откуда эти штуки вообще вылезли.

Перерыл статьи, обглодал видео — накопал дофига. Сначала поделился с коллегами в команде, теперь решил вывалить на вас. В этой статье я собрал всё, что, по моему скромному убеждению, надо знать про корутины.

Читать далее

👉 JS
Post #3671 416
Ну что, народ, Nuxt 4.5 выкатили.

Серьезный апдейт, без шуток. Там перетрясли три важнейших куска сборочной системы: Vite 8, Rspack 2, а еще добавили совсем новый пайплайн на Rsbuild для того самого Rspack.

Помимо этого, завезли экспериментальный стриминг SSR, нормальную систему кодов ошибок (наконец-то), кучу свежих композаблов с соглашениями и дофига внутренних улучшений. Все это потихоньку подтягивает нас к Nuxt 5.

Читать далее

👉 JS
Post #3669 427
Про антидетект-браузеры: зачем мы влезли в этот ад, когда там и так уже всё кишит

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

Кое-кто из вендоров кажет тебе что-то про антидетект, парсинг и ещё кучу тем, но их творение будто случайно затесалось не туда. В статье разбираемся, что это за зверь — антидетект-браузер, и как он вообще работает. Инфа из первых рук, без соплей.

Грызть дальше

👉 JS
Post #3665 387
Astra Studio: enterprise веб-приложение для взаимодействия с ИИ с нуля

Локальное веб-приложение, которое не шарит твои данные в облако. Агентная архитектура, навороченный RAG, MCP и мультимодальность — всё из коробки.

Репозиторий проекта: https://github.com/NeKonnnn/Astra-Studio

Читать далее

👉 JS
Post #3661 403
Как запилить типобезопасный клиент под Strapi

Есть одна засада с любым запросом к Strapi: что ты попросил — то и получишь. Дергаешь статью без populate — тебе кидают только скалярные поля. Втыкаешь populate: { category: true } — сразу подтягивается категория. А если туда же засунуть fields: ['name'], то категория придет уже урезанной.

Один и тот же эндпоинт способен выдать кучу разных форм, и статический TypeScript-интерфейс ни одну из них нормально не опишет: он либо лажает (обещает поля, которых в ответе нет), либо тупо any сидит.

В посте разбирают, как это дело пофиксить через кодогенерацию: берешь схему живого Strapi, генеришь по ней TypeScript-клиент, и система типов сама выводит форму ответа из аргумента populate еще на этапе компиляции. То есть как в Prisma: что передал в вызов — такой тип и возвращается. Код на TypeScript, клиент open-source под MIT, ссылка в конце.

Читать на Хабре

👉 JS
Post #3655 323
⁣WeakMap и кастомные деструкторы: когда using ломает GC

Связка WeakMap и using с Symbol.dispose выглядит элегантно, но в production может обернуться утечками и гонками. Главная проблема — сборщик мусора не синхронизирован с вызовами деструкторов, что ломает интуитивное поведение.

Грабли 1: Живой ключ в WeakMap

Код вида cleanupMap.delete(this) внутри [Symbol.dispose] не гарантирует очистку. Объект жив на момент вызова деструктора, и запись в WeakMap может висеть, если ключ захвачен в замыкании или передан наружу. Лучше проверять через has() перед удалением — это не спасет от всех кейсов, но снизит риск.

Грабли 2: Порядок финализации в WeakSet

Если несколько ресурсов с общими зависимостями финализируются через using, порядок вызова Symbol.dispose не определен. Проверка pool.has() внутри деструктора может дать race condition — один ресурс уже удален, другой еще жив. В высоконагруженных системах это ведет к нестабильности.

Грабли 3: Циклы через Symbol-ключи

Использование символа с собственным [Symbol.dispose] как ключа в WeakMap, который чистится в деструкторе ресурса, вызывает циклический вызов и stack overflow. Пример: const cleanupSymbol = Symbol('cleanup'); cleanupSymbol[Symbol.dispose] = () => map.delete(cleanupSymbol);. Такой паттерн лучше вообще избегать.

Производственные советы:

* Вместо WeakMap в деструкторах используй обычные Map с ручной очисткой — это предсказуемее.
* Для WeakSet не полагайся на консистентность между деструкторами — используй отдельные флаги состояния.
* Тестируй на разных движках JS: V8 и SpiderMonkey финализируют по-разному, баги всплывают не сразу.

Вывод: WeakMap и WeakSet в паре с using — мощный, но опасный инструмент, требующий явного контроля жизненного цикла ссылок, иначе GC и деструкторы превращают чистый код в источник трудноуловимых багов.
Post #3654 361
Зачем тебе бинарный поиск, если зарплату платят за покраску кнопок?

В айтишной тусовке вечный холивар: алгоритмы — это реально нужная в работе штука или просто развод на собеседованиях? Автор признаёт — сам сначала скептически ныл: «Нафига мне обход графа, если на проде я только CSS-отступы правлю?»

После расцвета AI этот треп стал только громче. Но чем глубже автор въезжал в алгоритмические задачки, тем чаще замечал, как они всплывают в бою: он реально научился собирать бизнес-фичи без лишней жести, быстрее находить узкие места, которые жрут производительность, и перестал сомневаться в своих действиях.

Читать далее

👉 JS
  • ❤ 1
Post #3652 340
Point0 — tRPC на стероидах, только без выноса мозга

Смотрю на Point0 и tRPC, и да, есть за что зацепиться. Квери и мутации в Point0 выглядят почти так же, как в tRPC, по ощущениям от разработки. Но вот фишка в том, что Point0 — это фреймворк, а не библиотека. А значит, у него есть суперсилы, которые библиотеке даже не снились.

Что он умеет:
— Квери и серверный код можно объявлять прямо в клиентских файлах. Или наоборот.
— При SSR автоматом гидрирует и дегидрирует квери на клиенте.
— В мутациях сам превращает файлы в FormData и обратно — без лишних телодвижений.
— У каждой квери и мутации стабильный личный URL.
— Редактор кода не тормозит, когда эндпоинтов становится дофига.
— С сервера на клиент прилетают целые серверные компоненты или интерактивные острова.
— Состояниями загрузки на страницах и в компонентах можно рулить прямо.

Это не всё, что умеет Point0, остальное — в других статьях. А пока фокус на сравнении с tRPC. Читать дальше

👉 JS
Post #3651 331
⁣Map.groupBy в production: неожиданные мутации групповых ключей и утечки памяти при использовании Symbol-ключей с WeakRef

Map.groupBy удобен для временной группировки, но в production легко наткнуться на два подводных камня, о которых документация умалчивает. Ошибки связаны с мутабельностью ключей и сборкой мусора при использовании Symbol.

Проблема 1: Мутация групповых ключей
Когда ключи группировки — объекты, Map.groupBy возвращает Map, где ключи — ссылки на те же объекты. Любое изменение исходного объекта ломает соответствие в группах. Например, сгруппировали пользователей по объекту с ролью, а потом поменяли роль — grouped.get(тот же объект) покажет старые данные.
const users = [{role: 'admin'}];
const grouped = Map.groupBy(users, u => u.role);
users[0].role = 'guest'; // мутация
grouped.get('guest'); // undefined, ключ 'admin' остался

Совет: используй только строки, числа или копии объектов, либо заморозь объекты через Object.freeze перед groupBy.

Проблема 2: Утечка памяти с Symbol-ключами и WeakRef
Symbol уникален и живёт, пока есть хоть одна ссылка. Если использовать Symbol как ключ в Map.groupBy, а потом потерять внешнюю ссылку — Symbol остаётся в Map, память не освобождается. WeakRef на Symbol не работает как слабая ссылка, так как Symbol не является объектом.
const key = Symbol('temp');
const grouped = Map.groupBy([1], () => key);
// ключ утечёт, даже после удаления внешней ссылки

Ошибка: полагаться на WeakRef для Symbol-ключей в production. Выход — использовать WeakMap с объектными ключами для краткосрочной группировки, либо явно чистить Map через delete.

Вывод: Map.groupBy в production требует контроля над мутациями ключей и управления памятью через примитивные ключи или явную очистку, иначе рискуешь получить неконсистентные данные и утечки.
Post #3649 339
Команда Далее раскатала историю: взяли тупую игрушку-тренажер по кибербезопасности и выкатили из нее самостоятельный продукт. Три отдельные консоли, редактор сценариев, боты для проверки и аудиочат на WebRTC — всё прикрутили.

Подробности на Хабре: Читать далее

👉 JS
Post #3643 314
⁣Atomics.pause() в спин-локах: когда хинт процессору превращается в баг кэш-когерентности

На первый взгляд, Atomics.pause() выглядит как безобидная микро-оптимизация: подсказываем процессору, что поток в спин-локе, и он сам оптимизирует кэш. В production с Worker-пулами на 8+ потоках и SharedArrayBuffer эта иллюзия разбивается о когерентность кэша и деградацию производительности.

Ложное пробуждение и протокол MESI
Atomics.pause() не даёт реальной задержки — процессор просто крутит микро-циклы. Когда десяток воркеров висят на Atomics.load() с прикрученным pause(), протокол когерентности (MESI) начинает бешено спамить состоянием Shared->Invalid. Кэш-промахи растут, latency скачет до 100 микросекунд. Типичная ошибка: думать, что pause() автоматически синхронизирует кэш — это не так, он лишь сообщает планировщику о намерении.

Дедлоки из-за локального кэша
Если пишешь цикл спин-лока только через Atomics.load() + pause(), без Atomics.wait(), то длительность паузы неопределённая. Поток может застрять на устаревшем значении в локальном L1-кэше из-за отсутствия барьера памяти. Пример из практики: в API-клиенте с shared очередь запросов на Node.js подняли буст, но через 30 секунд 25% запросов ушли в таймаут — поток просто не видел обновлённый флаг.
while (Atomics.load(flag, 0) !== DONE) {
Atomics.pause(); // баг: нет гарантии выхода
// счётчик ложноных выходов растёт
}

Практический совет: ограничь число итераций. Первые 10 — один pause(), до 100 — два, потом — Atomics.wait() с таймаутом. Иначе спин-лок съедает все такты ЦП.

NUMA-архитектуры и прыжки задержки
На AMD EPYC или Intel Xeon каждый pause() триггерит инвалидацию L1/L2, затем обновление через QPI или Infinity Fabric. Задержка скачет в 10-100 раз. В Worker-пуле, разбросанном по разным ядрам, это убивает пропускную способность. Решение — привязка воркеров к сокету через navigator.hardwareConcurrency (браузер) или os.setPriority (Node.js) с группировкой по архитектуре.

Предупреждение: не используй Atomics.pause() сам по себе в высоконагруженных пулах — это прямая дорога к деградации кэша и скачкам памяти. Тестируй под конкретный процессор.

Вывод: Atomics.pause() — это хинт, а не панацея, и в реальных спин-локах без комбинации с экспоненциальным backoff и Atomics.wait() он приносит больше вреда, чем пользы.
Post #3642 330
npm 12, TypeScript 7, и Bun на Rust

Зарелизили npm 12 — теперь скриптовые жизненные циклы выключены по дефолту. Это реально жирный апдейт, куча breaking-изменений. Лучше перед тем, как обновляться, воткнуть версию 11.18.0.

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

Автор Bun рассказал, как переписал свой JavaScript-рантайм с Zig на Rust. В процессе участвовала куча инстансов Claude Code, а API-доллар улетело ~$165k. Rust-версия станет базой для Bun 1.4, её ждут со дня на день.

Остальное: в выпуске #794.

👉 JS
  • 👍 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →