Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  • ru
    Игры
    Образование
    Искусственный Интеллект
    Новости
    Бекенд, разработка серверов
    Фронтенд
    Мобильная разработка
    Языки программирования
    Разработка игр | 3D | 2D
    Базы данных
    CMS
    Системное Администрирование
    Операционные системы
    Маркетинг
    Девайсы
    Сообщество
    Юмор, Мемы

  • en
    Humor
    News
    AI
    Programming languages
    Frontend
    GameDev

  • Блоги

Авторизуйтесь, чтобы написать сообщение

  • Все категории
  • hannadevH
    hannadev
    Object.fromEntries() и Map: чистые объекты настроек без мутаций и костылей

    Каждый день фронтендеры мучаются с настройками - конфигами, которые летают между функциями, мутируют под ногами и плодят баги. Object.fromEntries() с Map решает это чисто: берешь любой итерируемый набор пар ключ-значение и лепишь свежий объект без побочек. Забудь про ручные циклы и spread-операторы, которые иногда подводят.

    Это не просто сахар синтаксиса. Ты избегаешь мутаций оригинала, держишь код функциональным и читаемым. Полезно для парсинга query-параметров, трансформации API-ответов или создания дефолтных опций. Проблемы с глубоким клонированием? Они уходят сами.

    Почему Object.fromEntries() - антидот для конфигов

    Object.fromEntries() - это обратная сторона Object.entries(). Первый разворачивает объект в массив пар [ключ, значение], второй собирает обратно. Вместе они дают паттерн: entries() + map/filter + fromEntries(). Никаких мутаций, чистый иммутабельный флоу. Представь: у тебя Map с настройками из localStorage или URLSearchParams. Один вызов - и готов объект для пропсов компонента.

    Без этого приходится писать редусеры или Object.assign() в цикле - типичный легаси-костыль. А с fromEntries() код сжимается в одну строку, но остается предсказуемым. Плюс, Map держит ключи любого типа, в отличие от обычных объектов, где все строки. Это спасает при работе с символами или объектами как ключами.

    • Иммутабельность на стероидах: оригинальный Map или массив не трогается, всегда свежий объект.
    • Функциональный пайплайн: entries() -> transform -> fromEntries(), как в RxJS, но для JS.
    • Поддержка итерируемых: Map, Set, Array, даже generator - все на входе.
    • Нюанс с прототипом: свойства прототипа не попадают, только enumerable own properties.
    Подход Мутации Производительность Читаемость
    Цикл for…in Да Средняя Низкая
    Object.assign() Да Хорошая Средняя
    fromEntries() Нет Высокая Высокая

    Map как источник чистых настроек

    Map - идеальный контейнер для настроек на лету. new Map(Object.entries(config)) дает коллекцию без дубликатов ключей, плюс итерация for…of без entries(). Потом Object.fromEntries(map) - и объект готов. Полезно в утилитах: парсим query string в Map, фильтруем, собираем в config.

    Старый способ: lodash cloneDeep или JSON.parse/stringify - медленные, теряют функции и undefined. Map + fromEntries() - нативно, быстро, без потерь. Пример: API вернул Map с опциями, трансформируешь значения (добавляешь дефолты), и выдаешь объект для React/Vue.

    const queryMap = new URLSearchParams(window.location.search);
    const paramsObj = Object.fromEntries(queryMap.entries()); // { page: '1', limit: '10' }
    
    • Преимущества Map: дубликаты ключей перезаписываются, порядок сохраняется (с ES6).
    • Трансформация: map.entries().map(([k,v]) => [k, defaultValue(v)]).
    • Сравнение с WeakMap: не подходит, ключи должны быть объектами, но для настроек - overkill.
    • Интеграция с URLSearchParams: уже итерируемый, fromEntries() работает из коробки.

    Трансформации без рефакторинга всего проекта

    Классика: удвоить цены в объекте. entries() -> map(([key, val]) => [key, val*2]) -> fromEntries(). Код короче, чем reduce, и без мутаций. Это работает для filter: отсеиваем свойства по условию. Или sort по значениям - entries(), sort(), fromEntries().

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

    const settings = { theme: 'dark', lang: 'ru', debug: false };
    const validated = Object.fromEntries(
      Object.entries(settings).filter(([k,v]) => typeof v !== 'undefined')
    );
    
    • Фильтрация: entries().filter(([k,v]) => v > 0) - только положительные цены.
    • Маппинг: entries().map(([k,v]) => [k.toUpperCase(), v]) - нормализация ключей.
    • Комбо с reduce: редко нужно, fromEntries() эффективнее для простых случаев.
    • Порядок свойств: в объектах ES2015+ сохраняется порядок вставки, как в Map.
    Трансформация Старый способ Новый
    Удвоить значения for…in + obj[k]*=2 entries().map * fromEntries()
    Фильтр по значению reduce entries().filter() * fromEntries()
    Сортировка entries().sort() * reduce entries().sort() * fromEntries()

    Грабли, которых избежишь навсегда

    Не все итерируемые подходят: если ключи не строковые/символьные - в объекте станут строками. Map с числовыми ключами превратится в { ‘1’: value }. Проверяй типы заранее. Еще ловушка: undefined значения улетают без следа, fromEntries() их игнорирует.

    В старом коде часто видят Object.assign({}, …entries), но это мутирует target при ошибках. FromEntries() создает новый с нуля. Производительность: для 1000+ свойств Map быстрее, бандл меньше без lodash.

    • Ключи-объекты: теряются, станут [object Object]. Используй Map целиком.
    • Циклические ссылки: нет проблем, но в объекте могут быть.
    • Polyfill: если legacy-браузеры, но в 2026+ это не актуально.

    Реальные сценарии из подкапотного мира

    Парсинг форм: FormData.entries() прямо в fromEntries() - объект для отправки. Конфиг из env: Map из process.env, фильтр по префиксу, объект для app. В React: useMemo с fromEntries для theme-опций из context Map. Никаких useCallback костылей.

    Бонус: комбо с Proxy для реактивных config, но это уже next level. Или генераторы: function*() { yield [‘key’, val] }, потом fromEntries(). Код как по маслу.

    const formData = new FormData();
    formData.append('name', 'user');
    const config = Object.fromEntries(formData); // чистый объект
    

    Когда привыкнешь - старые циклы покажутся дикостью. Останутся вопросы с nested объектами? Рекурсивно entries() на значениях.

    Под капотом еще глубже

    Object.fromEntries() появился в ES2019, но под капотом - цикл по итератору с Object.defineProperty для каждого. Не используй на не-iterable - TypeError. Map.prototype.entries() возвращает пары, идеально ложатся. Сравни с Reflect: тот же эффект, но fromEntries короче.

    Это базовый brick для утилит: напиши toConfig(iterable) wrapper. Меньше deps в package.json. Думай о производительности: для больших Map - батчинг, но редко нужно.

    Когда иммутабельность бьет рекорды скорости

    Представь debounce-функции с опциями: Map из дефолтов, merge с user input через entries(), fromEntries() для финала. Никаких deep merges из ramda. В Node: парсинг multipart/form-data в config без мутаций.

    Грабли: fromEntries() не клонирует глубоко, nested объекты ссылаются. Для full clone - рекурсия. Но 90% случаев - плоские config, тут король.

    function mergeDefaults(userMap, defaultsMap) {
      return Object.fromEntries(new Map([...defaultsMap, ...userMap]));
    }
    
    • Merge Map: new Map([…defaults, …user]) перезаписывает user.
    • Deep merge: entries() на каждом, рекурсивно fromEntries.
    • Polyfill trap: самописный fromEntries падает на non-enumerable.

    Итог без иллюзий

    Object.fromEntries() с Map - минималистичный дуэт против мутационного ада. Конфиги чистые, код короткий, баги реже. За кадром: производительность на 10k+ items, где reduce проигрывает. Подумай о типизации в TS - entries() возвращает [string, any][], удобно для generics.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: гайды по апатии и мании спасают новичков, но механика все равно рвет

    Обложка: Pathologic 3: гайды по апатии и мании стали спасением но почему механика все равно ломает новичков

    Гайды по апатии и мании в Pathologic 3 стали настоящим спасением для новичков. Игроки разбирают шкалу настроения Бакалавра и учатся выживать без чтения скучных туториалов.

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

    Эти гайды фокусируются на системе, где центр шкалы - нейтральное состояние для Даниила Данковского. Сдвиг в апатию замедляет движение, в манию дает скорость, но жрет здоровье. Новички быстро осваивают тактики, избегая самоубийств и потерь HP. Для хардкора от Ice-Pick Lodge это меняет подход - практика вместо теории.

    Шкала апатии и мании: базовые эффекты

    Шкала в верхней части экрана смещается между апатией (слева) и манией (справа). Нейтраль - безопасная зона. Апатия растет от безделья или отвлеченных разговоров, мания - от прямолинейных реплик.

    • Максимум апатии: персонаж пытается самоубийство с QTE-событием (быстрое нажатие клавиш). Успех дает урон, но сбрасывает шкалу.
    • Максимум мании: здоровье тает, отображается иконкой сердца. Полезно для спринта через чумные зоны или бунты.

    Гайды подчеркивают: не держите строго центр. Высокая мания ускоряет перед таймингами, апатия помогает в диалогах с манией. Но новички все равно тонут - шкала качается непредсказуемо, особенно без лута.

    Как гайды учат балансировать

    Гайды заменяют встроенные подсказки практическими трюками. Режим концентрации (F или Q) подсвечивает объекты: красное для мании (баки, ящики), синее для апатии.

    Ключевые способы контроля:

    • Табак, стимуляторы - разгоняют манию.
    • Морфин, седативы - гасят апатию.
    • Диалоги: жесткие ответы повышают манию, болтовня - апатию.

    Не экономьте концентрацию, чтобы находить ресурсы. Амальгама тратится на лечение, лут собирайте системно. В первых днях это спасает от глупых смертей, но механика не прощает ошибок - толерантность к лекарствам растет, ресурсы кончаются.

    Состояние Эффект Тактика из гайдов
    Апатия max Замедление + QTE самоубийство Поднять морфином перед маниакальными диалогами
    Мания max Скорость + потеря HP Пробегать чуму с запасом лекарств
    Нейтраль Без рисков База для новичков, но не всегда оптимально

    Таблица показывает, почему гайды цепляют: они превращают абстрактную шкалу в инструмент выживания. Однако без опыта диалоги сбивают - половина вариантов не угадать заранее.

    Почему механика все равно ломает новичков

    Гайды дают старт, но Pathologic 3 - не линейный симулятор. Дефицит лута, чума, тайминги квестов давят. Апатия копится от простоя, мания жрет HP без запасов. Даже зная трюки, новички умирают на переходах или от неверных реплик.

    В обзорах отмечают: мания выгоднее апатии для скорости, но требует постоянного фарма лекарств. Туториалы в игре минимальны, гайды заполняют пробел. Последствия для игроков - либо осваиваешь через смерть, либо читаешь. Пока нет патчей, механика остается хардкорной, сбивая баланс без спойлеров.

    Что дальше для новичков

    Гайды эволюционируют: добавляют советы по дням 1-6, диагностике, взаимодействию с детьми. Известно, что окружение (бочки, поезда) влияет на шкалу. Не подтверждено влияние на сюжет - гайды избегают спойлеров. Для игроков это шанс пройти без фрустрации, но механика требует практики. Новичкам - запаситесь терпением.


    0 0 0 Ответить
  • AladdinA
    Aladdin
    Next js 16+ cacheComponents, переучиваемся кешировать, примеры

    Переход на Next.js 16 с флагом cacheComponents кардинально меняет философию работы с данными. Раньше фреймворк стремился все кэшировать и делал это неявно, а теперь по умолчанию все динамическое, и вы сами явно указываете, что хотите закэшировать.

    Это переход от модели “статики по умолчанию” к “динамике по умолчанию” с полным контролем разработчика. От себя скажу, что для разработчика это хорошо, меньше магии и больше понимания того что ты делаешь.

    История. Как Next.js переобулся

    Next.js 14

    Тут кешировалось все, что только могло кешироваться.

    Фреймворк по умолчанию стремился к статической генерации страниц (SSG) во время сборки. Он переключался на динамический рендеринг (SSR) только при обнаружении «динамических» функций, таких как cookies() или headers().

    // app/blog/[slug]/page.tsx
    
    export const dynamic = 'auto' // 'auto' | 'force-dynamic' | 'error' | 'force-static'
    export const dynamicParams = true // true | false
    export const revalidate = 3600 // false | 0 | number (в секундах)
    export const fetchCache = 'auto' // 'auto' | 'force-no-store' | 'only-cache' | ...
    

    Все fetch-запросы по умолчанию кэшировались (аналог cache: 'force-cache'). Это означало, что если вы не указывали опции явно, данные запрашивались один раз при сборке, и все пользователи видели одну и ту же версию

    // Данные будут получены один раз при сборке и закешированы навсегда.
    // Опцию cache: 'force-cache' можно не указывать, это значение по умолчанию.
    await fetch('https://api.example.com/posts', { cache: 'force-cache' });
    

    Next.js 15

    Самым значимым и обсуждаемым изменением в Next.js 15 стал полный пересмотр стратегии кэширования данных. Разработчики фреймворка прислушались к сообществу, которое часто сталкивалось с непредсказуемым поведением из-за агрессивного кэша в 14-й версии.

    📡 И вот теперь fetch() больше не кэширует данные.
    В Next.js 15 поведение по умолчанию изменилось на cache: ‘no-store’. Это значит, что каждый запрос fetch() будет выполняться заново при каждом обращении к странице, если вы явно не укажете иное. Это делает поведение в разработке и на продакшене более предсказуемым, но требует более осознанного подхода к оптимизации.

    🛣️ GET Route Handlers также стали динамическими
    Изменение коснулось и обработчиков маршрутов (Route Handlers). В 14-й версии GET-запросы кэшировались по умолчанию. В 15-й версии они также стали динамическими.

    Изменения затронули и клиентскую часть.
    В Next.js 14 кэш роутера на стороне клиента (Router Cache) по умолчанию сохранял посещенные страницы на 30 секунд для динамических и на 5 минут для статических страниц. В Next.js 15 клиентский кэш по умолчанию отключен для всех страниц. Теперь при переходе по страницам они будут загружаться заново, гарантируя, что пользователь всегда видит актуальную информацию. Если вам нужно ускорить навигацию и вы готовы пойти на компромисс, время жизни кэша можно настроить вручную в next.config.ts:

    // next.config.ts
    const nextConfig = {
      experimental: {
        staleTimes: {
          dynamic: 30, // 30 секунд для динамических страниц
          static: 180,  // 3 минуты для статических страниц
        },
      },
    };
    

    Next.js 16

    В 16-й версии Next.js добавляет флаг cacheComponents который действительно полностью меняет правила игры: он отключает всю старую модель кэширования и заменяет ее на новую, полностью явную. Всё, что вы знали о fetch, revalidate и export const dynamic раньше, больше не работает.

    Это все значит, что нам опять переучиваться ( ну, нам с @kirilljsx не привывать). Новые проблемы -> новая работа -> новые вакансии 😘 . Об этом всем можно и поныть, но на мой субъективный взгляд, надо было изначально делать таким фреймворк, а не подстраиваться под стадо вебмакак низшего эшелона добавляю свою магию везде, где нужно и не нужно.

    cacheComponents - Новая реальность

    Теперь, когда старые правила отключены, все решения о кэшировании принимаются явно и на уровне кода с помощью новой директивы ‘use cache’ и сопутствующих функций. Основной принцип прост: по умолчанию не кэшируется ничего.

    Директива 'use cache' — это ваш главный инструмент. Её можно применять на трех уровнях:

    1. На уровне файла (страницы или компонента): Поместите директиву в самом верху файла, и все экспортируемые из него асинхронные функции будут кэшироваться.

    2. На уровне компонента: Используйте директиву внутри тела компонента, чтобы закэшировать результат его рендеринга.

    3. На уровне функции: Применяйте к асинхронным функциям, чтобы кэшировать возвращаемые ими данные.

    cacheLife - Управление временем жизни кэша
    Для управления временем жизни кэша используется функция cacheLife. Она должна вызываться внутри области действия ‘use cache’.

    Вы можете использовать один из предустановленных профилей или создать свой собственный. Профили определяют три ключевых параметра: stale, revalidate и expire:

    Разберем подробнее, какой параметр за что отвечает.

    1. stale (Клиентский кеш)
      Определяет, как долго клиент (браузер) может показывать данные из кеша, вообще не связываясь с сервером для проверки.
      Пока не истечет это время, при повторном посещении страницы она загрузится мгновенно из памяти.
      Параметр чисто клиентской производительности, призванный ускорить навигацию.

    2. revalidate (Фоновая проверка)
      Частота, с которой кеш в фоновом режиме запрашивает свежие данные с сервера.
      Как только время revalidate истекает, Next.js все равно мгновенно отдает клиенту “устаревший” кеш, но в фоне запускает процесс генерации новой версии. Новые данные подготовятся к следующему запросу.
      Механизм stale-while-revalidate. Пользователь всегда получает быстрый ответ, даже если данные немного устарели.

    3. expire (Крайний срок)
      Максимальное время, в течение которого данные могут оставаться “устаревшими” до того, как они будут считаться полностью недействительными.
      Если данные в кеше находятся в состоянии “stale” (после revalidate) дольше, чем позволяет expire, Next.js больше не будет отдавать их мгновенно. Вместо этого он заблокирует ответ и заставит пользователя подождать, пока новые данные будут получены с сервера (динамический рендеринг).
      Защитный механизм от показа “совсем старых” данных. expire всегда должен быть больше revalidate.

    Профиль stale revalidate expire Описание
    'seconds' 30 сек 1 сек 1 мин Для контента, который должен обновляться почти мгновенно.
    'minutes' 5 мин 1 мин 1 час Для часто обновляемого контента.
    'hours' 5 мин 1 час 1 день Для контента, обновляемого несколько раз в день.
    'days' 5 мин 1 день 1 неделя Для контента, обновляемого ежедневно.
    'weeks' 5 мин 1 неделя 30 дней Для контента, обновляемого еженедельно.
    'max' 5 мин 30 дней 1 год Для очень стабильного контента.

    Важно: Если вы не укажете cacheLife, будет применен профиль ‘default’, который подходит для большинства случаев.

    включаем новый режим

    Для активации новой модели необходимо добавить флаг cacheComponents: true в ваш файл next.config.ts. Это глобальный переключатель, который меняет поведение всего приложения:

    // next.config.ts
    import type { NextConfig } from 'next'
    
    const nextConfig: NextConfig = {
      cacheComponents: true,
    }
    
    export default nextConfig
    

    Используем “use cache”

    На уровне файла (страницы)

    Если поместить ‘use cache’ в самом верху файла, она применяется ко всем экспортируемым асинхронным функциям в этом файле. Это удобно для кэширования целой страницы или группы связанных функций.

    // app/blog/page.tsx
    'use cache'; // <-- Директива на уровне всего файла
    
    import { cacheLife } from 'next/cache';
    
    // Эта функция тоже будет закэширована, так как она экспортируется и асинхронная
    export async function getFeaturedPosts() {
      // fetch без дополнительных опций, т.к. кэшированием управляет директива
      const res = await fetch('https://api.example.com/featured-posts');
      return res.json();
    }
    
    // Основной компонент страницы — экспортируемая асинхронная функция
    export default async function BlogPage() {
      cacheLife('hours'); // Устанавливаем время жизни кэша для всей страницы
    
      const posts = await getFeaturedPosts();
    
      return (
        <main>
          <h1>Блог</h1>
          {posts.map((post) => (
            <article key={post.id}>{post.title}</article>
          ))}
        </main>
      );
    }
    

    Важно: Если в этом же файле есть синхронные компоненты (например, function Sidebar()), они не попадают под действие ‘use cache’, потому что директива влияет только на асинхронные экспорты.

    На уровне компонента

    В этом случае директива помещается внутрь тела асинхронного компонента. Она кэширует результат рендеринга этого конкретного компонента.

    // app/components/ProductList.tsx
    import { cacheLife, cacheTag } from 'next/cache';
    
    export async function ProductList({ category }: { category: string }) {
      'use cache'; // <-- Директива внутри компонента
      cacheLife('days');
      cacheTag(`products-${category}`); // Тег для точечной инвалидации
    
      const products = await fetch(
        `https://api.example.com/products?category=${category}`
      ).then((res) => res.json());
    
      return (
        <div className="grid">
          {products.map((product) => (
            <div key={product.id}>{product.name}</div>
          ))}
        </div>
      );
    }
    Как использовать на странице:
    
    tsx
    // app/products/page.tsx
    import { Suspense } from 'react';
    import { ProductList } from '@/components/ProductList';
    
    export default function ProductsPage() {
      return (
        <div>
          <h1>Товары</h1>
          {/* Этот компонент будет закэширован */}
          <ProductList category="electronics" />
          
          {/* А этот останется динамическим, так как не обёрнут в 'use cache' */}
          <Suspense fallback={<p>Загрузка рекомендаций...</p>}>
            <PersonalRecommendations />
          </Suspense>
        </div>
      );
    }
    

    На уровне функции

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

    // app/lib/data.ts
    import { cacheLife, cacheTag } from 'next/cache';
    
    // Кэшируемая функция получения данных
    export async function getUserProfile(userId: string) {
      'use cache'; // <-- Директива на уровне функции
      cacheLife('minutes');
      cacheTag(`user-${userId}`);
    
      console.log('Выполняется запрос к БД'); // Увидим только при первом вызове
      const user = await db.user.findUnique({ where: { id: userId } });
      return user;
    }
    

    Использование в компонентах:

    // app/profile/page.tsx
    import { getUserProfile } from '@/lib/data';
    
    export default async function ProfilePage() {
      const user = await getUserProfile('user-123'); // Кэшируется
    
      return (
        <div>
          <h1>Привет, {user.name}!</h1>
          <UserDetails user={user} />
        </div>
      );
    }
    

    Если getUserProfile вызвать ещё раз в другом компоненте на той же странице, запрос к БД не повторится — Next.js вернёт закэшированный результат.

    💡 Дополнительно: Комбинирование уровней

    Вы можете комбинировать директивы. Например, страница закэширована целиком, но внутри есть функция, у которой свой собственный cacheLife.

    // app/dashboard/page.tsx
    'use cache'; // Кэшируем всю страницу
    
    import { cacheLife } from 'next/cache';
    import { getStats } from '@/lib/stats';
    
    export default async function DashboardPage() {
      cacheLife('hours'); // Основное время жизни для страницы
    
      const stats = await getStats(); // Функция getStats может иметь свой 'use cache' и cacheLife
    
      return <Dashboard stats={stats} />;
    }
    
    // app/lib/stats.ts
    import { cacheLife } from 'next/cache';
    
    export async function getStats() {
      'use cache';
      cacheLife('minutes'); // Этот кэш будет обновляться чаще, чем вся страница
    
      const res = await fetch('https://api.example.com/stats');
      return res.json();
    }
    

    В этом случае общий HTML страницы будет жить по правилам hours, а данные из getStats — по правилам minutes, но они всё равно встроены в статический каркас страницы.

    🛑 Подводные камни (Важно!)

    Не все так гладко, просто так включить флаг и пользоваться скорее всего не выйдет, если вы не подготовили проект к такому переходу 🤡

    Когда вы включаете cacheComponents в Next.js 16, фреймворк переходит к новой стратегии рендеринга — Partial Prerendering (PPR). В её основе лежит жёсткое требование: во время сборки (next build) должен быть сформирован мгновенно загружаемый статический “каркас” (static shell). Из-за этого асинхронное получение данных без 'use cache' и без <Suspense> приводит к ошибке сборки Uncached data was accessed outside of <Suspense>.

    Причина ошибки: блокировка статического каркаса
    Раньше Next.js мог “подождать” данные и отдать готовую страницу (SSR), но с cacheComponents он всегда пытается сгенерировать статическую оболочку на этапе сборки.

    Проблема возникает, когда в компоненте есть асинхронный вызов (например, fetch или await params), который не может завершиться во время сборки и при этом не обрамлён. В этом случае сборка падает с ошибкой.

    Если фреймворк не знает, что показывать пользователю, пока данные грузятся (нет fallback из ), он не может собрать статический каркас. Это защита от “медленной” страницы, где пользователь видит белый экран до полной загрузки всех данных на сервере.

    Как исправить: два пути на выбор

    У вас есть два варианта решения этой ошибки, в зависимости от ваших задач:

    1. Закэшировать данные в статический каркас: Если данные меняются редко, их можно сделать частью мгновенно загружаемого каркаса. Для этого нужно добавить директиву 'use cache' прямо в асинхронную функцию. Тогда данные будут получены на этапе сборки и закэшированы.

    2. Оставить данные динамическими, но с заглушкой: Если данные должны запрашиваться при каждом визите (персонализированная информация, часто меняющиеся данные), их нужно обернуть в <Suspense>. Это указывает Next.js оставить в статическом каркасе “заглушку” (fallback), а сами данные догрузить уже на клиенте в фоне.

    ( кейсы попробую подготовить далее в комментариях)

    Как это работает?

    🧱 Статический каркас (Static Shell) — что это?

    Когда вы включаете cacheComponents, Next.js перестаёт генерировать страницу целиком динамически на сервере по каждому запросу. Вместо этого он во время сборки (build) пытается создать каркас страницы — мгновенно загружаемый HTML, который видит пользователь в первую секунду.

    Внутри этого каркаса могут быть:

    • Статический контент (заголовки, подвалы).
    • Закэшированные данные.
    • “Дырки” (Suspense Fallback) для тех данных, которые ещё не готовы.

    ⚙️ Как именно кеш помогает отрисовать этот каркас?

    Ответ кроется в том, в какой момент времени выполняется код.

    Без кеша (ошибка сборки)

    // ❌ Ошибка при сборке
    export default async function Page() {
      const data = await fetch('...'); // Запрос без 'use cache'
      return <div>{data}</div>;
    }
    

    Во время сборки Next.js запускает этот компонент.

    Он натыкается на await fetch. Стоп-машина. Потому что по новым правилам fetch по умолчанию динамический (no-store).

    Next.js не может выполнить динамический запрос во время сборки (в окружении CI/CD нет контекста пользователя, да и смысла нет — данные же должны быть свежими при каждом запросе).

    Next.js не знает, что рисовать в этом месте каркаса, и выбрасывает ошибку: “Я не могу собрать статику, потому что тут висит незавершенный асинхронный хвост”.

    С кешем (успешная сборка)

    // ✅ Успешная сборка
    export default async function Page() {
      'use cache'; // <-- Включаем кеш
      const data = await fetch('...');
      return <div>{data}</div>;
    }
    
    1. Выполнение во время сборки: Директива 'use cache' говорит фреймворку: "выполни этот fetch прямо сейчас, во время npm run build !!! ".

    2. Сохранение результата: Next.js делает запрос к API, получает ответ и сохраняет его в кеш (на диск или в CDN).

    3. Генерация HTML: Next.js берет полученные данные, рендерит их в HTML-строку

      Данные из кеша
      и вшивает этот HTML прямо в файл page.html.

    4. Результат: Пользователь, заходя на сайт, мгновенно получает готовую страницу с уже встроенным текстом “Данные из кеша”.

    💡Если данные нужны свежие, но каркас тоже нужен?

    Тут в игру вступает <Suspense> Он позволяет обмануть сборку.

    // ✅ Сборка проходит, данные свежие
    import { Suspense } from 'react';
    
    async function FreshData() {
      const data = await fetch('...'); // Нет 'use cache'
      return <div>{data}</div>;
    }
    
    export default function Page() {
      return (
        <main>
          <h1>Статический заголовок</h1>
          <Suspense fallback={<div>Загрузка данных...</div>}>
            <FreshData />
          </Suspense>
        </main>
      );
    }
    

    Как здесь помогает кеш? В этом примере кеша нет, но сборка всё равно проходит. Почему? Потому что физически вырезает проблемный компонент FreshData из процесса статической сборки.

    Во время build:

    1. Next.js рендерит <h1>Статический заголовок</h1>.

    2. Доходит до . Вместо того чтобы лезть внутрь FreshData, он просто записывает в HTML строку <div>Загрузка данных...</div>(то, что в fallback).

    3. Каркас готов! FreshData при сборке не вызывается вообще.

    4. Когда пользователь открывает страницу, он видит “Загрузка…”, а React на клиенте (или сервере при стриминге) запускает FreshData, получает свежие данные и заменяет заглушку на реальный контент.


    1 0 1 Ответить
  • GameFishG
    GameFish
    Pathologic 3: гайды по апатии и мании хитом, но туториалы отпугивают новичков

    Обложка: Pathologic 3: гайды по апатии и мании стали хитом но почему туториалы все равно отпугивают новичков

    Гайды по механике апатии и мании в Pathologic 3 разлетелись по сети - они стали спасением для игроков, пытающихся осилить выживание в Новом Мор. Эти туториалы объясняют ключевую систему настроения бакалавра Данковского, но базовые туториалы игры всё равно сбивают с толку новичков и повышают порог входа.

    Игроки хвалят внешние гайды за конкретику: как балансировать шкалу, избегать самоубийства от апатии или истощения от мании. Это важно, потому что без понимания механики первые часы игры превращаются в фрустрацию - персонаж ползёт улиткой или тает на глазах. Для Pathologic 3, где каждый день на счету, такие гайды меняют подход к прохождению.

    Шкала апатии и мании: как это работает

    В верхней части экрана видна шкала между апатией (синий конец) и манией (красный). Нейтральная зона по центру - безопасная, но редко держится сама по себе. Апатия растёт от безделья, стояния на месте или отвлечённых диалогов, замедляя движение до ползуна. На максимуме герой пытается самоубийство - нужно быстро жать клавиши, чтобы выжить, но урон всё равно берётся.

    Мания ускоряет бег, показывает путеводные линии в режиме концентрации (F), но жрёт здоровье - иконка сердца мигает. Высокая мания полезна для спринта через чумные зоны или бунты, если есть запас лекарств. Гайды подчёркивают: не бойся перекосов, если ресурсы под контролем.

    Способы контроля: таблетки, окружение, диалоги

    Контроль шкалы - комбо из расходников и окружения. Вот основные методы из гайдов:

    • Стимуляторы и табак разгоняют манию, морфин и седативы гасят апатию. Толерантность растёт, так что дозировку придётся увеличивать.
    • Окружение: пианино, скрипящие колонки повышают манию (красное свечение в F-режиме), качели и карусели успокаивают (синие). Обычно срабатывает раз.
    • Диалоги: жёсткие, торопливые ответы - к мании (экран мигает красным), отвлечённые болтовня - к апатии (синий). Предугадать можно в половине случаев.

    Гайды учат использовать перекосы тактически: морфин перед диалогом с риском мании или мания для рывка по карте.

    Почему туториалы игры проваливаются

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

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

    Последствия для игроков и игры

    Для новичков гайды - must-read перед стартом: с них начинается реальное выживание, а не рандомная смерть. Pathologic 3 выигрывает от комьюнити-контента - он снижает отток, но подчёркивает слабость онбординга от разработчиков.

    Пока неизвестно, выйдет ли патч с улучшенными туториалами. Игроки продолжают полагаться на внешние ресурсы, что типично для артхаусных тайтлов с глубокими, но opaque механиками.


    0 0 0 Ответить
  • hannadevH
    hannadev
    Set vs filter/includes: убираем дубли ID товаров без тормозов на большом списке

    У тебя массив с тысячами ID товаров, и дубли плодятся как грибы после дождя. Хочешь их убрать быстро, без лагов в UI. Разберём Set против классики filter + includes - что взлетает на реальных данных, а что проваливается.

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

    Почему includes тормозит на больших списках

    Array.includes ищет линейно - каждый вызов шарит по всему массиву с начала до конца. Для 10k элементов это O(n) на итерацию, а если зациклить в filter - вообще O(n^2). Представь: корзина с 5k ID, и ты фильтруешь дубли 100 раз в секунду на скролле.

    На мелких массивах разница незаметна, но при росте данных UI начинает чихать. Браузер тратит миллисекунды на каждый has, а их тысячи. Set.has же хэширует и находит за O(1) - просто брось массив в конструктор, и готово.

    Реальный кейс: список товаров из API, где ID повторяются из-за пагинации. Includes жрёт 200мс на 20k элементов, Set - 5мс. Переход меняет отзывчивость.

    • Линейный поиск в includes: каждый элемент проверяется заново, даже если дубли в начале.
    • Хэш-таблица в Set: мгновенный доступ по ключу, независимо от размера.
    • Память: Set жрёт чуть больше из-за хэш-мапы, но на 10k+ окупается скоростью.
    Подход Сложность Время на 10k элементов Время на 100k
    filter + includes O(n^2) ~150мс ~15с
    new Set(array) O(n) ~3мс ~25мс
    […new Set(filter)] O(n) ~5мс ~40мс

    Filter с Set: комбо для сложных случаев

    Часто нужно не просто дубли убрать, а отфильтровать по условию и дубли стереть. Классика - array.filter(item => allowedIds.includes(item.id)). Здесь includes снова бьёт по производительности, особенно если allowedIds большой.

    Создай Set из allowedIds заранее - new Set(allowed), потом filter(item => allowed.has(item.id)). has летает, filter остаётся читаемым. Для объектов с ID это золотая середина: не переписывай под Map полностью.

    Пример из жизни: таблица товаров, фильтр по категории + наличие. allowedIds из стора - 3k штук, основной список 15k. Без Set - лаги на каждой смене фильтра, с Set - мгновенно.

    • Подготовка: const uniqueIds = new Set(bigArray.map(id => id));
    • Фильтр: products.filter(p => uniqueIds.has(p.id));
    • Spread в массив: если нужен Array - […uniqueSet];

    Нюанс: Set хранит уникальные значения, для объектов нужен глубокий хэш или Map по ID.

    const duplicates = [1,2,2,3,1,4,5,5];
    const unique = [...new Set(duplicates)]; // [1,2,3,4,5]
    
    // Фильтр с Set
    const allowed = new Set([2,4,6]);
    const filtered = bigList.filter(id => allowed.has(id)); // O(n)
    

    Когда Set не панацея - альтернативы под капотом

    Set крут для примитивов, но с объектами или строками длинных ID хэш-коллизии могут подтормаживать. Плюс, если массив уже отсортирован - два указателя быстрее всего.

    Сортируй array.sort((a,b)=>a-b), потом иди двумя индексами: i и j. На пересечении дубли ловятся за O(n log n + n). Для ID товаров из БД часто уже sorted - профит.

    Ещё вариант: Map по ID для объектов. new Map(products.map(p => [p.id, p])). Доступ по ключу O(1), и дубли сами отсекаются при set.

    • Сортировка + указатели: идеал для sorted данных, без доп. памяти.
    • Map для объектов: сохраняет первую встреченную копию.
    • Reduce как костыль: работает, но читаемость хуже Set.
    Сценарий Лучший выбор Почему
    Примитивы ID Set O(1) lookup
    Объекты по ID Map Полный объект в значении
    Sorted массив Два указателя Нет хэша, минимум памяти
    Маленькие списки Includes Код проще, разница не видна

    Масштаб на миллионах - трюки из продакшена

    На 100k+ ID Set всё равно жрёт память - каждый entry 8 байт + overhead. Если UI рендерит таблицу, подумай о виртуальном скролле + ленивом unique.

    Разбей на чанки: process chunks по 10k, собирай Set по частям. Или используй WeakSet для GC-friendly, если ID временные.

    В реальном екоме: каталог 500k товаров, уникализация по сессии. Set на клиенте + debounce на ввод - фризы ушли, но следи за утечками при частых обновах.

    • Чанкинг: array.slice(0,1e4), Set, merge.
    • WeakSet: для disposable данных, GC чистит сам.
    • IndexedDB оффлайн: для персистентных больших списков.

    Тестируй в prod-like: Chrome DevTools Performance, реальные данные.

    Грабли, которые убивают перф даже с Set

    Забыл spread - Set не итерируется везде. Или создаёшь new Set в render-лупе Vue/React - перерендеры жрут CPU.

    Хуже: мутируешь оригинал .add() в цикле, теряешь реактивность. Делай копию заранее.

    Ещё засада - NaN и -0 в Set ведут себя как уникальные, хотя == false. Для числовых ID норм, но проверь.

    • Луп в рендере: вынеси в useMemo / computed.
    • Мутация: const copy = […set]; не трогай original.
    • Edge-кейсы: document.querySelectorAll в Set - NodeList не примитивы.

    Код без компромиссов

    Соберём итоговый snippet для типичного кейса: уникальные ID товаров из корзины + фильтр.

    function dedupeProductIds(products, allowedCategories) {
      const catSet = new Set(allowedCategories);
      const idSet = new Set();
      
      return products
        .filter(p => catSet.has(p.category))
        .filter(p => idSet.size < 10000 && idSet.add(p.id).size === 1) // лимит памяти
        .map(p => p.id);
    }
    

    Производительность на уровне, код читается. Масштабируй под свои данные.

    Что Set не заменит в архитектуре

    Set решает локальные дубли, но если уникальность из API - фиксай на бэке. Клиент не для тяжёлой логики.

    Подумай о нормализации стора: Map<id, product> в Redux/Zustand. Дубли исчезают по определению, поиск O(1). Для миллионных списков - шаг вперёд.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Доменные LLM для разработчиков: кастомное обучение и CI/CD интеграция

    Обложка: Доменные LLM для разработчиков: как обучать кастомные модели на корпоративных данных и интегрировать в CI/CD

    Представьте: ваша команда тратит часы на разбор корпоративных документов, FAQ и внутренних регламентов, а чат-боты отвечают шаблонно и мимо кассы. Доменные LLM решают это на корню - дообучаем модель на ваших данных, и она выдает релевантные ответы по нишевой тематике, повышая точность на 12-25% без утечек в облако.

    Доменная LLM - это не игрушка, а инструмент для бизнеса. В отличие от универсальных моделей вроде GPT, которые жуют весь интернет и путаются в специфике (финансы, право, ремонт оборудования), доменные фокусируются на отрасли. Берем open-source базу вроде Llama 3 или DeepSeek-V3 (671B параметров, MoE-архитектура, бьет GPT-4.5 по матеше и коду), дообучаем на внутренних данных - диалогах, инструкциях, отчетах. Результат: бот понимает жаргон, генерит код под ваш стек, анализирует риски транзакций.

    Шаг 1: Подготовка данных - основа всего

    Данные - 80% успеха. Собираем анонимизированные диалоги, FAQ, регламенты. Чистим, структурируем с доменными экспертами. Инструменты: HuggingFace datasets для загрузки, SuperAnnotate для разметки (настраиваемые интерфейсы + ИИ-автоматизация).

    • Анонимизация: Убираем PII (личные данные) - критично для приватности.
    • Качество: Фильтруем шум, балансируем классы (например, типовые вопросы vs редкие кейсы).
    • Формат: Инструкции в стиле “Запрос: [текст]. Ответ: [релевантный].” для fine-tuning.

    Без этого модель будет галлюцинировать. В банке, скажем, научили на диалогах - и релевантность выросла на 25%.

    Шаг 2: Дообучение с PEFT - экономим ресурсы

    Полное обучение жрет GPU-фермы, но PEFT (Parameter-Efficient Fine-Tuning) меняет игру. LoRA-адаптеры трогают 1% параметров базовой модели, дообучаем на одной A100 за часы.

    Выбираем модели для корпоративного деплоймента 2026:

    Модель Параметры Плюсы Минусы
    DeepSeek-V3 671B (MoE) Бьет GPT-4.5 по коду/матеши, tool-calling Требует мощного железа
    GLM-4.5-Air 106B (MoE) Оптимизация под агентов, веб/код Меньше контекста (131K)
    Qwen3-235B 235B Универсал для RAG/агентов Лицензия под вопросом

    Практика: Python-скрипт для LoRA на HuggingFace. Устанавливаем: pip install transformers peft bitsandbytes datasets. Запускаем дообучение.

    from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer
    from peft import LoraConfig, get_peft_model
    import torch
    from datasets import load_dataset
    
    model_name = "meta-llama/Llama-3-8B"
    model = AutoModelForCausalLM.from_pretrained(model_name, load_in_8bit=True)
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    
    dataset = load_dataset("json", data_files="your_corporate_data.json", split="train")
    
    def tokenize_function(examples):
        return tokenizer(examples["text"], truncation=True, max_length=512)
    
    tokenized_dataset = dataset.map(tokenize_function, batched=True)
    
    lora_config = LoraConfig(
        r=16, lora_alpha=32, target_modules=["q_proj", "v_proj"], lora_dropout=0.05
    )
    model = get_peft_model(model, lora_config)
    
    training_args = TrainingArguments(
        output_dir="./lora_adapter",
        num_train_epochs=3,
        per_device_train_batch_size=4,
        gradient_accumulation_steps=4,
        learning_rate=2e-4,
        fp16=True,
    )
    
    trainer = Trainer(model=model, args=training_args, train_dataset=tokenized_dataset)
    trainer.train()
    model.save_pretrained("corporate_llm_adapter")
    

    Это базовый пайплайн. Адаптер сохраняем отдельно - легко версионировать.

    Шаг 3: Интеграция в CI/CD - автоматизация на проде

    Дообучил - пора в прод. Развертываем on-premise: скачиваем модель на сервер с GPU (офис или корпоративное облако), интегрируем в CI/CD через GitHub Actions или GitLab CI.

    • Docker: Контейнерим с vLLM для инференса (быстрее TorchServe).
    • CI пайплайн: Тесты на датасете, валидация метрик (BLEU, ROUGE для текстов), автодеплой адаптера.
    • Kubernetes: Масштабируем под нагрузку, мониторим с Prometheus.
    • RAG-бонус: Добавляем векторный поиск (FAISS/Pinecone) для свежих данных без переобучения.

    Пример GitHub Action: на пуше в main - тест, дообучение на новых данных, деплой. Безопасность: все локально, без OpenAI-подобных утечек.

    В РФ это актуально: open-source тренд + локальные GPU позволяют обходить санкции, дообучать на своих серверах. Сервисы вроде DataFinder уже дают российскую инфраструктуру.

    Что дальше для вашей команды?

    Доменные LLM окупаются быстро: автоматизация документооборота, кодогенерация, бизнес-аналитика. Но ключ - в пайплайне: данные + PEFT + CI/CD. Не гонитесь за гигантами - начните с LoRA на 8B-модели, профит увидите через неделю.

    А вы уже дообучаете свои LLM на корпоративке? Как впихиваете в CI/CD и какие модели юзаете на проде? Делитесь в коммах, разберем кейсы вместе!


    1 0 0 Ответить
  • hannadevH
    hannadev
    Object.fromEntries против for: объект из формы за 3 строки вместо 20

    Каждый раз, когда форма на фронте вырастает до 10+ полей, код сбора настроек превращается в спагетти из циклов и условий. Вместо этого есть Object.fromEntries - метод, который из FormData делает чистый объект за одну строку. Это избавляет от boilerplate, утечек в ивент-лупе и бесконечных рефакторингов.

    Зачем копаться в forEach или reduce, если нативный API решает задачу чище? Размер бандла не растет, производительность на уровне, а код читается как конфиг. Сегодня разберем, как это работает под капотом и почему мидлы наступают на старые грабли с ручными циклами.

    Классический for-of: почему это костыль

    Когда форма простая - два-три инпута, никто не заморачивается. Но добавь селекты, чекбоксы, группы - и начинается. Ты проходишься for-of по элементам формы, проверяешь name, тип, значение. Если чекбокс не чекнут - вручную false впихиваешь. Радио-кнопки? Еще один if. Итог - 20 строк, где половина - edge cases.

    Под капотом это работает стабильно, но код разрастается линейно с числом полей. Добавь валидацию - еще 10 строк. А если форма динамическая, с клонируемыми блоками? Цикл ломается на дублирующихся name. Плюс каждый такой for - потенциальная утечка памяти, если забыл почистить ссылки на DOM. Реальный пример из легаси-проектов: объект настроек собирают в useEffect, и рендеры тормозят из-за лишних перестроений.

    Вот типичный шаблон, на который наступают:

    • Проверка if (element.name) - пропускаем безымянные элементы.
    • Для checkbox: obj[element.name] = element.checked.
    • Для select multiple: отдельный цикл по options.
    • Преобразование типов: parseInt или JSON.parse для сложных значений.
    Ситуация For-of строки Проблемы
    Простая форма (5 полей) 8-12 Уже boilerplate
    С чекбоксами/радио 15-25 Edge cases множатся
    Динамические поля 30+ Ломается на дублях

    Object.fromEntries: как это работает нативно

    Метод берет итерируемый объект пар [key, value] и лепит из него объект. Для форм идеально подходит FormData - она уже итерируется как надо. Object.fromEntries(formData) - и вуаля, чистый объект настроек. Никаких циклов, никаких if.

    Под капотом FormData реализует @@iterator, который выдает пары по name/value автоматически. Чекбоксы? Нативно false если не чекнуты. Select multiple? Массив значений. Даже file input кидает File объект без танцев. Производительность? На уровне reduce, но без аллокаций промежуточных массивов. В бенчмарках на больших формах fromEntries быстрее for-of на 20-30%, потому что движок оптимизирует итераторы лучше ручных циклов.

    Ключевые фичи, которые спасают:

    • Автоматическая обработка disabled полей - их просто нет в итераторе.
    • Поддержка append() для массивов в динамических формах.
    • Immutable результат - оригинальная FormData не мутируется.
    • Работает везде с ES2019, полифил не нужен в современных браузерах.

    Пример трансформации:

    const formData = new FormData(form);
    const settings = Object.fromEntries(formData); // { theme: 'dark', notify: 'true', items: ['a', 'b'] }
    

    Edge cases и как их фиксить без боли

    Не все формы идеальны - бывают кастомные name вроде ‘user[name]’, nested объекты или boolean флаги. Object.fromEntries кидает плоский объект, так что для nests нужен постпроцессинг. Но даже тут проще, чем в цикле: один Object.fromEntries + reduce для группировки.

    Представь форму с подгруппами: shipping[city], billing[zip]. Нативно получишь { ‘shipping[city]’: ‘Moscow’ }. Чтобы распаковать - пишешь mapper. Или используешь FormData.append с плоскими ключами заранее. Чекбоксы без значения? FormData их пропустит, так что дефолтный объект задаешь merge’ом: Object.assign(defaults, Object.fromEntries(formData)). Производительность не страдает - один проход.

    Типичные грабли и фиксы:

    • Дублирующиеся name (массивы): FormData сам собирает в array-like, fromEntries делает массив.
    • Nested keys: пост-обработка через пути вроде lodash.set, но лучше 3 строки на reduce.
    • Type coercion: new FormData сам парсит строки, для чисел - +value в mapper.
    • Empty form: возвращает {}, без ошибок.
    Проблема For-of фикс fromEntries фикс
    Чекбокс unchecked if (!checked) obj[name] = false defaults + merge
    Multiple select вложенный цикл нативный массив
    Nested поля ручной split/join reduce по паттерну

    Когда fromEntries выигрывает по производительности

    На мелких формах разница в 3 строки vs 10 - вопрос стиля. Но при 20+ полях или динамике код взрывается. Тестировал на форме с 50 полей: for-of жрет 1.2ms, fromEntries - 0.8ms в Chrome. В ивент-лупе на submit разница копится, особенно если валидация с ререндерами.

    Бонус: в React/Preact это идеально ложится в onSubmit. Нет нужды в сторонних libs вроде formik - нативно и быстро. Минус? Старые браузеры до ES2019, но их <1% трафика. Полифил - 2kb, но лучше feature detect. Под капотом движок использует тот же machinery, что и Object.entries, симметрично и предсказуемо.

    Фичи для перфоманса:

    • Нет промежуточных массивов - прямой итератор.
    • Оптимизировано V8 для частых вызовов в формах.
    • В комбо с structuredClone - безопасный сериализация настроек.

    Три строки, которые меняют рефакторинг

    Object.fromEntries сокращает не только строки, но и когнитивную нагрузку - фокусируешься на логике, а не на парсинге. Осталось за кадром: интеграция с URLSearchParams для query-строк или кастомные итераторы для legacy форм. Подумай, сколько for-of в твоем коде можно выкинуть - и бандл станет легче.

    В реальных проектах это правило: если >5 полей - fromEntries. Динамика? FormData + append в runtime. Главное - меньше ручных циклов, чище дебаг и меньше багов на граблях с типами.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: гайды по апатии и мании заменяют скучные туториалы

    Обложка: Pathologic 3: гайды по апатии и мании спасают новичков от туториалов

    Гайды по механике апатии и мании в Pathologic 3 стали спасением для новичков. Вместо чтения встроенных туториалов игроки сразу разбирают шкалу настроения Бакалавра и учатся выживать без лишней воды.Эти советы помогают быстро освоить баланс между замедлением от апатии и скоростью от мании, избегая самоубийств и потери здоровья. Для хардкорной игры от Ice-Pick Lodge это меняет подход: гайды дают практические тактики, а не спойлеры сюжета.## Шкала апатии и мании: как это работает

    В Pathologic 3 верхняя часть экрана показывает шкалу, где центр - нейтральное состояние для Даниила Данковского. Сдвиг влево - апатия, вправо - мания. Апатия растет от безделья или отвлеченных разговоров, мания - от прямолинейных реплик.Апатия замедляет движение: на максимуме Бакалавр пытается самоубийство с QTE-событием. Даже успех дает урон, но сбрасывает шкалу. Мания ускоряет персонажа, идеально для чумных районов или бунтов, но истощает здоровье - мигает иконка сердца.Не всегда цель - центр шкалы. Иногда полезно качнуть в крайность: морфин перед эмоциональным диалогом повышает апатию, чтобы не скатиться в манию.## Тактики управления из гайдов

    Гайды учат использовать окружение и предметы. Режим концентрации (F) подсвечивает объекты: красное - для мании (баки, ящики), синее - для апатии.Ключевые способы баланса:

    • Табак или стимуляторы разгоняют манию.
    • Морфин и седативы успокаивают апатию.
    • Диалоги: жесткие ответы - мания, болтовня - апатия.- В клетке на пятый день апатия растет сама - борись манией медикаментами.Высокая мания с запасом лекарств позволяет носиться по карте, экономя время. Толерантность растет, так что ресурсы тратятся быстрее.## Почему гайды лучше туториалов
    Встроенные подсказки в Pathologic 3 минимальны и философские, не объясняют механики четко. Гайды от сообщества дают списки, таблицы рисков и тактики без спойлеров сюжета.Для новичков это критично: игра - квест с выживанием, где апатия/мания влияет на диалоги, скорость и исходы. Гайды показывают, как не умирать глупо в первые дни. Состояние Эффект Как использовать
    Апатия max Самоубийство QTE Перед диалогами с манией
    Мания max Скорость + урон HP Чумные зоны, тайминги ## Перспективы и что дальше

    Гайды продолжают множиться: от демо до полного прохождения. Пока неясно, как патчи изменят баланс толерантности или QTE. Но механика остается ключевой для Бакалавра - без нее Новый Мор съест новичков за час.


    0 0 0 Ответить
  • hannadevH
    hannadev
    Set vs Array: удаляем дубликаты в тегах без лишних костылей

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

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

    Чем Set отличается от Array

    Массив - это индексированная коллекция. Значения упорядочиваются по позиции: нулевой элемент, первый, второй. Каждый раз, когда нужно проверить, есть ли уже такой элемент, приходится либо использовать indexOf(), либо перебирать весь массив циклом. Для массива с тысячей тегов это быстро становится боль.

    Set - это совсем другое животное. Это коллекция ключей, где каждое значение хранится только один раз. Когда вы пытаетесь добавить дубликат, Set просто его проигнорирует. Нет никаких проверок перед вставкой - это встроено в саму структуру данных.

    • Индексированность: Array упорядочивает по индексам (0, 1, 2…), Set упорядочивает по ключам
    • Уникальность: Array хранит всё, Set автоматически отбрасывает дубликаты
    • Производительность проверки: Array требует линейного поиска, Set проверяет за O(1)
    • Порядок элементов: Оба сохраняют порядок вставки, но только Array позволяет быстро обратиться по индексу

    Как Set обрабатывает примитивы и объекты

    Вот тут начинается самое интересное. Set работает с примитивами (строки, числа, boolean) по значению, а с объектами по ссылке.

    Если у вас массив тегов вроде ['react', 'vue', 'react', 'angular'] - Set справится за миллисекунду. Преобразовываем в Set и обратно в массив:

    const tags = ['react', 'vue', 'react', 'angular'];
    const uniqueTags = [...new Set(tags)];
    // Результат: ['react', 'vue', 'angular']
    

    Но если вы решили хранить теги как объекты {name: 'react'}, вот тут Set ловит косяк. Даже если два объекта выглядят идентично, это разные ссылки в памяти:

    const tagObjects = [{id: 1}, {id: 1}, {id: 1}];
    const uniqueTagObjects = new Set(tagObjects);
    console.log(uniqueTagObjects.size); // 3, не 1!
    

    Почему так? Потому что Set сравнивает объекты по ссылке, а не по содержимому. Каждый {id: 1} - это разные адреса в памяти. Если вам действительно нужно дедублицировать объекты, придётся писать свою логику или использовать Map с кастомным ключом.

    • Примитивы: Сравниваются по значению - два одинаковых числа считаются дубликатом
    • Объекты: Сравниваются по ссылке - два объекта с одинаковыми свойствами это разные элементы
    • Смешанные типы: 1 (число) и '1' (строка) - разные значения, Set оба сохранит
    • Null и undefined: Сохраняются по одному экземпляру

    Производительность: цифры говорят сами за себя

    Если вы слышали, что Set быстрее - это не маркетинг, это факт. Тесты на реальных объёмах данных показывают: Set быстрее Array с filter в десятки раз, а reduce в сотню раз.

    Когда вы вызываете arr.indexOf() или arr.includes() для проверки наличия элемента, браузер проходит весь массив с начала. Это O(n) операция. Повторяем проверку для каждого элемента - получаем O(n²). Set использует хеш-таблицу внутри и проверяет за O(1). Для массива из тысячи элементов разница измеряется в порядках величины.

    Сравните эти подходы:

    Подход Код Скорость
    Set [...new Set(arr)] Базовая
    Filter + indexOf arr.filter((v, i) => arr.indexOf(v) === i) ~10x медленнее
    Reduce arr.reduce((acc, v) => acc.includes(v) ? acc : [...acc, v], []) ~100x медленнее
    Цикл с проверкой for + arr.includes() ~20x медленнее
    // Измеряем самый быстрый способ
    const testArray = Array.from({length: 10000}, (_, i) => i % 100);
    
    console.time('Set approach');
    const result1 = [...new Set(testArray)];
    console.timeEnd('Set approach'); // ~1ms
    
    console.time('Filter approach');
    const result2 = testArray.filter((v, i) => testArray.indexOf(v) === i);
    console.timeEnd('Filter approach'); // ~50ms
    

    Методы Set для работы с тегами

    Kогда вы знаете, какие методы есть, работать с Set становится проще. Вот что вам нужно для обработки тегов:

    • set.add(value) - добавить тег в множество, дубликаты игнорируются автоматически
    • set.has(value) - проверить, есть ли тег уже в множестве (быстро, за O(1))
    • set.delete(value) - удалить конкретный тег
    • set.clear() - очистить всё множество
    • set.size - узнать количество уникальных тегов

    Практический пример - обработка тегов поста:

    const postTags = new Set();
    
    // Добавляем теги пользователя
    postTags.add('javascript');
    postTags.add('frontend');
    postTags.add('javascript'); // Игнорируется
    
    // Проверяем наличие
    if (postTags.has('javascript')) {
      console.log('Тег уже есть');
    }
    
    // Итерируем в порядке добавления
    postTags.forEach(tag => console.log(tag));
    // javascript, frontend
    
    // Удаляем ненужное
    postTags.delete('frontend');
    console.log(postTags.size); // 1
    

    Итерация всегда происходит в порядке вставки элементов. Это важно - если вы хотите сохранить порядок тегов, как их вводил пользователь, Set не подведёт.

    Когда Array ещё может быть полезен

    Не преувеличивайте, Set - не серебряная пуля. Есть сценарии, где Array всё ещё нужен.

    Если вам нужно частно обращаться по индексу - Array выигрывает. tags это O(1), а из Set элемент по номеру не достать. Также если вы работаете с очень маленькими коллекциями (пара десятков элементов), производительность Set не будет видна, а код может быть понятнее с привычным Array.

    Для древних браузеров (IE10 и ниже) Set просто не существует - придётся fallback’ить на Array. И если вы делаете какой-то специфический обход или трансформацию данных, Array методы могут быть удобнее.

    // Array vs Set: когда Array проще
    const tags = ['react', 'vue', 'angular'];
    
    // Нужна трансформация каждого элемента
    const tagsByLength = tags.map(tag => tag.length);
    // Set это не может делать встроенно
    
    // Нужна фильтрация по условию
    const longTags = tags.filter(tag => tag.length > 5);
    // Set тоже не может
    
    // Нужен доступ по индексу
    const firstTag = tags;
    // Set заставит конвертировать в массив
    

    Практический паттерн: обработка тегов поста

    Большинство задач с дедупликацией тегов решаются одинаково. Вот универсальный подход, который работает в 90% случаев:

    function getUniqueTags(rawTags) {
      // rawTags может быть грязным - с пробелами, дубликатами, пустыми строками
      return [
        ...new Set(
          rawTags
            .map(tag => tag.trim().toLowerCase())
            .filter(tag => tag.length > 0)
        )
      ];
    }
    
    const userInput = ['React', 'REACT', ' vue ', '', 'Angular', 'react'];
    const cleanTags = getUniqueTags(userInput);
    console.log(cleanTags);
    // ['react', 'vue', 'angular']
    

    Всё чётко: сначала нормализуем данные через map и filter, потом Set отрезает дубликаты, потом разворачиваем обратно в массив.

    • Нормализация перед Set: Приводим к одному формату (lowercase, trim), убираем пустоту
    • Set деплицирует: Одна операция, всё работает
    • Разворот в массив: Если нужен массив дальше, используем spread или Array.from()
    • Сохранение порядка: Set гарантирует порядок вставки

    На чём не стоит зацикливаться

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

    Третье заблуждение - что нужны сложные полифиллы для старых браузеров. Set поддерживается везде, где нужно (IE11+, современные браузеры). Если вы ещё поддерживаете IE10, это вообще отдельная проблема, не только для Set.

    И последнее - что производительность Set магична в каждом случае. Set быстрее именно на проверках уникальности и дедупликации больших объёмов. На маленьких массивах разница незаметна.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: рейтинг 87% на Steam, но критики не стихают через 3 месяца

    Обложка: Pathologic 3: рейтинг подскочил до 87% но критика не утихает после трех месяцев

    Pathologic 3 вышел три месяца назад и быстро набрал 87% положительных отзывов на Steam. Несмотря на высокий рейтинг, споры в сообществе не утихают - игроки продолжают разбирать сильные и слабые стороны игры.

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

    Рейтинг и динамика отзывов

    Pathologic 3 стартовал с смешанными реакциями, но со временем рейтинг подскочил до 87%. Это произошло за счет притока новых игроков, привлеченных атмосферой и сюжетом. Однако свежие обзоры все равно полны замечаний.

    Общий подъем связан с несколькими факторами:

    • Атмосфера и нарратив: Многие хвалят историю, написанную в соавторстве с командой, что добавило глубины по сравнению с предыдущими частями.
    • Технические улучшения: Оптимизация под современное железо и Steam сделали игру доступнее.
    • Долгая поддержка: Разработчики из Ice-Pick Lodge выпустили патчи, исправившие баги на запуске.

    Несмотря на цифры, негатив держится на уровне 13% - это отзывы от тех, кто не смог переварить кор-механики.

    Основные точки критики

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

    • Геймплейные косяки: Сложность выживания все такая же адская, но управление и интерфейс все еще сырые. Многие жалуются на неудобную инвентаризацию и медленный темп.
    • Сюжетные линии: Множество веток квестов хвалят за нелинейность, но часть игроков называет их запутанными, с необязательными провалами.
    • Технические проблемы: Хотя патчи помогли, на слабом ПК фризы и вылеты остаются. Консольные версии тоже под вопросом - пока только ПК.

    Таблица сравнения отзывов по платформам (на основе Steam-данных):

    Аспект Положительные отзывы Отрицательные отзывы
    Атмосфера 92% 5%
    Геймплей 78% 18%
    Графика 85% 10%
    Сюжет 89% 8%

    Реакция сообщества и разработчиков

    Сообщество раздвоилось: ветераны Pathologic радуются эволюции серии, новички делятся мемами о “мор” и провалах. Форумы вроде DTF полны разборов - от восторгов по саундтреку до фрустрации от пермадета.

    Разрабы из Ice-Pick Lodge отреагировали патчами и обещаниями доработок. Алексей Поляков (он же Поляринов) делился тревогами перед релизом, но сейчас фокус на контенте. Пока не подтверждено:

    • Выход на консоли.
    • Новые DLC или сюжетные обновления.
    • Глобальный ремастер первой части.

    Это держит хайп, но и раздражает тех, кто ждет конкретики.

    Итог споров

    Через три месяца Pathologic 3 стоит крепко на 87%, подтверждая статус нишевой жемчужины. Критика по геймплею и техчасти не сломала рейтинг, но показывает, куда смотреть Ice-Pick Lodge. Для игроков это сигнал: если атмосфера и нарратив в приоритете - берите, иначе подождите патчей.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    AI-native платформы: как ИИ меняет процесс разработки

    Обложка: AI-native платформы для разработчиков: как писать код поверх ИИ и не сломать SDLC

    Проблема: разработчиков не хватает, сроки горят, рутина убивает

    Реальность такова - дефицит разработчиков только растет, а заказчики требуют результатов вчера. Классический SDLC с его водопадом, спринтами и code review начинает выглядеть как средневековье, когда у тебя есть ИИ, который может писать тесты, архитектуру и даже генерировать документацию. Проблема в том, что большинство команд до сих пор используют ИИ как помощника - ставят Copilot в IDE и ждут чуда. А это не работает. Нужно переосмыслить сам процесс разработки с нуля.

    AI-native платформы - это не Copilot в VS Code. Это полноценные среды разработки, где генеративный ИИ встроен на уровне инфраструктуры: от генерации кода до деплоя, тестирования и даже проектирования архитектуры.

    Как это вообще работает на практике

    Представь, что ты говоришь платформе: “Сделай CRM для ритейла с интеграцией БД”. На выходе платформа собирает тебе стек - React на фронте, Node.js на бэке, PostgreSQL в качестве БД. Но это не просто каркас. Автоматически добавляются:

    • Генерация кода для основных операций
    • Тесты (unit и интеграционные)
    • CI/CD конфиги
    • Базовая документация
    • Даже проверка безопасности

    Теоретически, команда из 3-5 человек может создавать то, что раньше требовало 20-30 разработчиков. И Gartner не шутит - к 2030 году 80% организаций будут использовать именно такую модель.

    ТОП инструментов в 2026 году

    Практически используемые платформы делятся на несколько категорий:

    Облачные платформы с нативной поддержкой ИИ:

    • SiliconFlow - универсальная облачная платформа с бессерверным выводом и выделенными GPU (NVIDIA H100/H200). Подходит, если нужна высокая пропускная способность и полная поддержка LLM
    • Microsoft Azure - корпоративный монстр с прямой интеграцией OpenAI, чипом MAIA 100 и бесшовным подключением к Microsoft-экосистеме. Если в компании уже Office 365 и Teams - это выбор
    • AWS + Google Cloud - классика, но требует больше ручной настройки

    IDE и редакторы для разработчиков:

    • Claude Code - #1 по рейтингам разработчиков в 2026. Почему? Потому что Claude хорош в понимании контекста и не генерирует откровенный мусор
    • Cursor - лучший AI-редактор для повседневной работы. Интегрируется с твоим стеком, понимает твой проект
    • Windsurf - лидер по версии LogRocket, специализируется на IDE-опыте

    No-code/Low-code платформы для MVP:

    • FlutterFlow - конструктор мобильных приложений с возможностью экспорта кода на React Native. Важно: ты не заперт внутри платформы, можешь взять код и дорабатывать вручную
    • OnSpace.AI - максимально быстрый запуск. Описываешь идею, платформа собирает фронт, логику и базу данных
    • Draftbit - для тех, кто хочет больше контроля. Визуальная сборка + работа с логикой на уровне, близком к реальной разработке

    Как организовать workflow, чтобы не сломать всё

    Вот тут начинается интересное. Просто взять и использовать ИИ везде - это рецепт хаоса.

    GitHub Agent HQ (февраль 2026) дал нам классный пример: запусти Claude, Codex и Copilot одновременно на одной задаче, каждый оценит компромиссы по-своему, а затем выбери лучший вариант.

    На практике успешные команды организуют работу так:

    1. Отдельные агенты для отдельных задач: один для code review, другой для генерации тестов, третий для проверки безопасности, четвёртый для деплоя
    2. Каждый агент специализируется на своём, но все работают согласованно
    3. Человек остаётся в loop для критических решений и архитектурных выборов

    При этом обязательно нужно установить правила ограниченной автономии для ИИ-агентов в продакшене. Иначе получишь ситуацию, когда система сама решила refactorить production код в 3 ночи.

    Практический пример: система промптирования для code generation

    Вот системный промпт, который реально работает для генерации кода через ИИ:

    Ты - Senior Full-Stack Developer.
    
    Когда ты пишешь код:
    1. Всегда добавляй type hints (TypeScript/Python)
    2. Логируй критические операции (DB queries, API calls)
    3. Генерируй unit-тесты параллельно с кодом
    4. Предполагай, что код может упасть - добавляй error handling
    5. Для API endpoints - генерируй примеры запросов в документацию
    
    Что НЕ делай:
    - Не генерируй код без валидации входных данных
    - Не создавай SQL-запросы через конкатенацию строк
    - Не забывай о CORS и security headers
    - Не генерируй пароли или секреты в code
    
    Дополнительные требования:
    - Node.js + TypeScript для бэка
    - React + TypeScript для фронта
    - PostgreSQL для БД
    - Придерживайся REST API standards
    

    Да, это звучит как обычный code review-лист. Потому что это и есть code review, только в виде инструкции ИИ.

    Реальность для российского рынка

    Отличная новость - большинство платформ работают. Плохая - западные решения (Claude, ChatGPT, Gemini) имеют ограничения доступа из РФ из-за санкций. Но DeepSeek занимает второе место по доле российской аудитории среди ИИ-чатботов, а отечественные решения типа GigaChat от Сбера и Яндекс.Алиса уже разворачиваются под разработку. Облачные платформы вроде SiliconFlow работают и имеют поддержку доменных LLM.

    Так что если ты в РФ - используй то, что доступно. DeepSeek + локальные облачные платформы + open-source модели - это реальное направление прямо сейчас.

    Вопрос к аудитории

    А как вы организуете процесс работы с ИИ в разработке? Используете отдельные агенты для отдельных задач или пока стоите на классическом коде с Copilot? И главное - в какой момент вы поняли, что ИИ-генерируемый код стал настоящей проблемой, а не помощью?


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    6G для ИИ-разработчиков: настройка роботов и AR/VR в 2026 году

    Обложка: 6G-инфраструктура для разработчиков ИИ: как настраивать приложения для роботов и AR/VR в 2026

    Представьте: ваш робот на складе теряет миллисекунды на задержку в сети, и вся цепочка поставок стоит. Или AR-очки в VR-тренировке лагают, клиенты уходят к конкурентам. 6G решает это радикально: задержка в миллисекунды, гигабитные скорости и ИИ прямо в сети. Для разработчиков ИИ это значит приложения для роботов и AR/VR, которые работают как часы, без компромиссов. В 2026 стандарты 6G стандартизируются, прототипы уже тестят, а Nvidia собирает альянс для AI-RAN.

    Ключевые фичи 6G для ИИ-приложений

    6G - это не просто быстрее 5G. Это инфраструктура для физического ИИ: дроны, роботы, AR/VR с сенсорным восприятием. Основное:

    • Задержка 1-2 мс: критично для робототехники и голографической связи. Робот реагирует мгновенно на команды.
    • Скорости до 16+ Гбит/с: прототипы Qualcomm уже показывают 16,6 Гбит/с вниз. AR/VR стримы 8K без буферинга.
    • AI-RAN: ИИ в ядре сети от Nvidia. Автооптимизация трафика, предиктивное покрытие.
    • Гибридные вычисления: edge + cloud + device. Данные с сенсоров обрабатываются на периферии.
    • Многослойное покрытие: наземные + спутниковые сети для seamless handover.

    В России прорывы есть: инновационные материалы для 6G, планы Роскомнадзора на ИИ в радиоинтерфейсе и AR для погружения. Сколтех и ВШЭ пилотируют цифровые двойники сетей.

    Настройка приложений: практика для роботов и AR/VR

    Разработчики, пора адаптировать код под 6G API. Ожидайте открытые стандарты с встроенным ИИ. Для роботов - реал-тайм контроль, для AR/VR - мультисенсорный фид.

    Вот пример на TypeScript для мобильного AR-аппа с 6G edge-вычислениями. Используем WebRTC + гипотетический 6G SDK (на базе 5G NSA, эволюционирует в 2026).

    import { EdgeAIClient } from '@6g-edge/sdk'; // Прототип SDK от Qualcomm/Nvidia
    
    import type { SensorData, ARFrame } from './types';
    
    class RobotARController {
      private client: EdgeAIClient;
    
      constructor(networkId: string) {
        this.client = new EdgeAIClient(networkId, {
          latencyTarget: 1.5, // мс
          aiOptimization: true // AI-RAN автонастройка
        });
      }
    
      async processRobotFrame(sensorData: SensorData): Promise<ARFrame> {
        // Сенсоры -> edge ИИ -> AR оверлей
        const optimized = await this.client.infer(sensorData, {
          model: 'physical-ai-robot',
          computeSplit: 'edge-heavy' // 80% на периферии
        });
    
        return {
          overlay: optimized.visuals,
          commands: optimized.actions // Для робота
        };
      }
    
      // Реал-тайм стрим для VR
      startARStream(callback: (frame: ARFrame) => void) {
        this.client.stream('ar-vr-channel', (data) => {
          callback(this.processRobotFrame(data));
        });
      }
    }
    
    // Использование
    const controller = new RobotARController('ru-6g-pilot');
    controller.startARStream((frame) => console.log('AR ready:', frame));
    

    Этот код подключается к 6G RAN, делегирует ИИ на edge (нейроморфные чипы в планах), минимизирует latency. Для Python аналог на FastAPI + 6G libs от Huawei/Nokia. Тестируйте на 5G-тестбедах сейчас - профит в проде.

    Фича 5G 6G Выгода для ИИ
    Latency 10-20 мс 1-2 мс Роботы без сбоев
    Скорость 1-10 Гбит/с 16+ Гбит/с 8K AR/VR стримы
    ИИ-интеграция Опционально В ядре (AI-RAN) Автооптимизация

    Вызовы и реальность для РФ

    В 2026 стандартизация в разгаре, Qualcomm целит Олимпиаду-2028. Россия отстает в коммерции, но лидирует в материалах и ИИ для спектра. Для бизнеса в РФ: пилоты в Москве/СПб через МТС/Роскомнадзор. Импорт чипов под санкциями - фокус на отечественные аналоги от HSE. Стоит ли инвестировать? Да, если вы в робототехнике или enterprise AR - ROI через 2-3 года за счет edge ИИ.

    Что дальше для ваших проектов?

    6G меняет игру: от лагов к физическому ИИ. Инвестируйте в SDK сейчас, тесты на прототипах дадут edge над конкурентами. А вы уже мигрируете роботов/AR на 6G-ready стек? Какие latency-боли в проде и как решаете? Делитесь в комментах - разберем кейсы вместе!


    0 0 0 Ответить
  • hannadevH
    hannadev
    Object.entries + Map против for: парсинг плоского JSON в группы за 5 строк кода

    API часто кидает плоский JSON - сплошной массив объектов без группировки. Хочешь по категориям разложить - пишешь for на 50 строк с if-ами и push. А можно Object.entries + Map за 3-5 строк. Это решает проблему раздутого кода и утечек в логике.

    Зачем это нужно: группировка ускоряет рендер списков, фильтры и поиск. Без нее фронт тонет в nested циклах. Покажу, как парсить заказы по статусам или товары по брендам - чисто, без костылей.

    Плоский JSON из API: типичная яма

    API возвращает массив заказов: каждый объект с id, status, amount, date. statuses - это ‘pending’, ‘shipped’, ‘delivered’. Хочешь сгруппировать по статусам для дашборда. Ручной for: проверяешь status, пушить в массив группы, нуляешь счетчики. Легко накосячить - забыть else, дубли push или off-by-one в индексах.

    Пример данных:

    const orders = [
      {id:1, status:'pending', amount:100},
      {id:2, status:'shipped', amount:200},
      {id:3, status:'pending', amount:150}
    ];
    

    В итоге groups = {pending: , shipped: […]}. Но код разрастается: if для каждого status, else для default. А если статусов 10? Boilerplate душит.

    • Проблема 1: Ручной for не масштабируется - добавь статус, допиши if.
    • Проблема 2: Легко сломать порядок вставки или пропустить элемент.
    • Проблема 3: Нет size или быстрого .has() - приходится Object.keys().length.
    Подход Строк кода Масштабируемость Ошибки
    for + if 30-50 Плохо Часто
    Map 3-5 Отлично Минимально

    Object.entries: почему это твой новый друг

    Object.entries(obj) выдает [[key, value]] - готовый массив для Map или reduce. Из плоского объекта в итерируемый формат за 1 строку. Идеально для JSON.parse, где ключи строковые, а значения - любые.

    Пример: у тебя конфиг {theme:‘dark’, lang:‘ru’}. entries дает [[‘theme’,‘dark’], [‘lang’,‘ru’]]. Теперь forEach или map - как по масиву. Без entries пришлось бы for…in с hasOwnProperty - легаси 2010-х.

    Ключевой трюк: new Map(Object.entries(flatObj)). Map сохраняет порядок вставки, ключи любого типа (не только строки, как в объекте).

    • entries vs keys: keys() - только ключи, теряешь значения. entries - полная пара.
    • Нюанс: entries не рекурсивно - только own properties, прототипы игнорит.
    • Когда entries выигрывает: группировка, где ключ - динамический (userId, timestamp).
    const config = {theme:'dark', lang:'ru'};
    const mapConfig = new Map(Object.entries(config));
    console.log(mapConfig.get('theme')); // 'dark' - O(1)
    

    Map для группировки: 5 строк вместо 50

    Берем плоский массив orders. Цель: groups = new Map(), где ключ - status, значение - массив заказов. Ручной способ: forEach с if status === ‘pending’ ? groups.pending.push : else if…

    С Map: orders.forEach(order => { const group = groups.get(order.status) || []; group.push(order); groups.set(order.status, group); }). 4 строки. Или one-liner с reduce.

    Полный код:

    const groups = orders.reduce((acc, order) => {
      const group = acc.get(order.status) || [];
      group.push(order);
      acc.set(order.status, group);
      return acc;
    }, new Map());
    

    Map.get/set - быстрее Object[key], особенно с нестроковыми ключами.

    • Преимущество 1: Map сохраняет порядок вставки - первый pending будет первым в массиве.
    • Преимущество 2: .size вместо Object.keys().length - короче, быстрее.
    • Преимущество 3: .delete(key) - чисто удалить группу без undefined.
    Операция Object Map
    Получить размер Object.keys(obj).length obj.size
    Проверить ключ ‘key’ in obj obj.has(‘key’)
    Удалить delete obj.key obj.delete(‘key’)
    Итерация for…in for…of obj.entries()

    Таблица сравнения: for vs entries + Map

    Ручной for хорош для 2-3 групп. Добавь ‘cancelled’, ‘refunded’ - код мутирует в монстра. entries + Map - динамично: статусы из данных, без hardcode.

    Бенчмарк на 10k items: for ~15ms, Map ~12ms. Разница в реальном app - в читаемости и багфиксах. Map не ломается при NaN ключах или Symbol.

    Реальный кейс - парсинг логов API: group by endpoint, count errors.

    • For: if (item.status === ‘error’) errors++; else if…
    • Map трюк: new Map().set(endpoint, (map.get(endpoint)||0) +1 )
    • fromEntries обратно в obj: Object.fromEntries(groups) - для localStorage.
    Сценарий Ручной for Map-вариант Выигрыш
    5 статусов 40 строк 4 строки x10 короче
    Динамические ключи Переписать Работает Без багов
    Фильтр + group Nested loops chain .filter().reduce Читаемо

    Когда Map под капотом ломается

    Map жрет памяти под хеш-таблицу - для 1M items подумай WeakMap. Но для фронта (до 50k) - ок. Не сериализуется в JSON напрямую - stringify(Map) = {}. Фикс: Object.fromEntries(map.entries()).

    Итерация: for (let [status, list] of groups) renderList(list). Порядок как в данных - не как Object.keys (enum order).

    Подведем: entries + Map - антидот boilerplate в парсинге. Осталось за кадром: группировка по нескольким полям (composite key как ${cat}-${brand}) и интеграция с React/Vue keys. Подумай, где в твоем коде висит for на 50 строк - замени, сэкономь час дебага.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Angular 2026: от корпоративного монстра к быстрому фреймворку с супер-рендерингом

    Обложка: Angular 2026: от корпоративного монстра к быстрому фреймворку с супер-рендерингом и легким дебагом

    Представьте: ваш корпоративный фронтенд на Angular жрет 200+ МБ на загрузку, SSR тормозит как черепаха, а дебаг - сплошной ад с зонами и Observable. Бизнес стонет от медленных лидов, разрабы тратя время на костыли вместо фич. Angular 2026 это меняет: Zoneless по умолчанию, Signals в ядре, супер-рендеринг и дебаг как в React. Теперь билд летает, apps весят в разы меньше, а код чище без NgModules.

    Супер-рендеринг: SSR + Hydration на стероидах

    Angular 21+ сделал Zoneless Change Detection стандартом. Нет больше Zone.js, который пухнул бандлы и путал дебаг. Signals заменяют RxJS в простых кейсах: реактивность без подписок, эффекты пересчитываются только по зависимостям. Результат? Гидратация в 2-3 раза быстрее, TTI (Time to Interactive) падает до 1-2 сек даже на слабых девайсах.

    Плюс component-level code splitting: каждый роут лениво грузится, tree-shaking вырезает мертвый код на уровне компонентов. В продакшене ng build генерит dist/ с минифицированными чанками, где серверный рендер (node dist/server/server.mjs) работает из коробки. Бизнесу профит: SEO на высоте, Core Web Vitals зеленые, конверсия растет.

    Легкий дебаг: Signals и Standalone без boilerplate

    Забудьте модули: Standalone Components - норма. Импортируешь прям в bootstrap, DI работает через providers в компоненте. Signals упрощают стейт: сигнал меняется - view обновляется только там, где нужно. Нет диффов по всему дереву.

    Пример простого контрола с Signals (TypeScript, Angular 21+):

    import { Component, signal, effect, computed } from '@angular/core';
    
    @Component({
      selector: 'app-counter',
      standalone: true,
      template: `
        <p>Count: {{ count() }}</n>
        <p>Double: {{ double() }}</p>
        <button (click)="increment()">+</button>
      `
    })
    export class CounterComponent {
      count = signal(0);
      double = computed(() => this.count() * 2);
    
      constructor() {
        effect(() => console.log(`Count changed to: ${this.count()}`));
      }
    
      increment() {
        this.count.update(v => v + 1);
      }
    }
    

    Здесь effect логирует изменения автоматически, без ручных destroy. Дебаг в DevTools: signals видны как reactive graph, ошибки локализованы. В Vite-билде (новый дефолт) хот-рилоад секунды.

    От монстра к ракете: миграция и реалити

    Миграция с 13-19 на 21+? Реально за 2-3 спринта: CLI миграции чистят NgModules, добавляют signals. Команды типа Compo B2B прошли это - код стал декларативнее, релизы не пугают. Webpack под капотом оптимизирует AOT, minify и bundling - apps летают на любом хостинге.

    В РФ это актуально: банки, e-com и госкорпорации на Angular сидят годами. С Zoneless и SSR деплой на Yandex Cloud или VK Cloud проще, latency падает. Минус? RxJS еще нужен для сложных потоков, но signals его вытесняют. Стоит учить - вакансий море, зп от 300k.

    Что дальше для вашего стека?

    Angular 2026 - не хайп, а рабочий инструмент для масштаба. Он экономит время разрабов на дебаге, деньги бизнеса на инфраструктуре. Перешли на signals + standalone? Как SSR влияет на ваши метрики? Делитесь в коммах: мигрировали ли вы, или держитесь за старый Angular? Давайте обсудим реальные кейсы.


    0 0 0 Ответить
  • hannadevH
    hannadev
    Map vs Object: почему ключи-объекты становятся [object Object] и крашат кэш сессий

    Map и Object кажутся похожими, но ключи-объекты в Object превращаются в “[object Object]” и затирают данные. Это бьет по кэшу сессий, когда userId как объект улетает в никуда. Разберем под капотом, почему так происходит и как фиксить без костылей.

    В сессионном кэше часто хранят данные по объектным ключам - типа {userId: {data}}. Object их строкует, и разные объекты сливаются в одну строку. Map держит ссылки как есть. Это спасает от коллизий в реальных проектах с авторизацией и state.

    Как Object ломает ключи-объекты

    Object в JS - это не коллекция, а хэш-таблица со строковыми ключами. Любое значение, не строка или Symbol, преобразуется через toString(). Объект по умолчанию дает “[object Object]”, функция - “function …()”. Поэтому два разных userId-объекта сливаются в одну запись.

    Представь кэш сессий: генеришь уникальный объект для пользователя, кладешь данные. Следующий запрос - новый объект, но ключ строкует в то же “[object Object]”. Старые данные перезаписываются. Краш: сессия теряет состояние, пользователь видит чужие данные или пустоту.

    Вот классическая засада:

    • Создаешь const cache = {};
    • const user1 = {id: 123}; cache[user1] = 'session1';
    • const user2 = {id: 123}; cache[user2] = 'session2';
    • console.log(cache[user1]); // 'session2' - коллизия!

    Реальный пример из сессий:

    const sessionCache = {};
    function getSession(userObj) {
      return sessionCache[userObj] || 'new';
    }
    const u1 = {id: 1};
    const u2 = {id: 1};
    sessionCache[u1] = 'user1 data';
    console.log(getSession(u2)); // 'user1 data' - но должно быть undefined
    

    Нюанс: Даже если объекты “равны” по содержимому, ссылки разные - Object их не различает после toString().

    Map держит ссылки без принуждения

    Map - настоящая коллекция ключ-значение без строкования. Ключ остается объектом, сравнивается по ссылке через ===. Размер через .size, итерация через for…of. Идеально для динамических ключей в кэше.

    В сессиях: генерируешь объект-ключ один раз на userId, держишь в Map. Последующие запросы используют тот же объект или WeakMap для GC. Нет коллизий, производительность на частых set/get выше Object при >100 записях.

    Перепишем кэш:

    const sessionCache = new Map();
    const u1 = {id: 1};
    const u2 = {id: 1};
    sessionCache.set(u1, 'user1 data');
    console.log(sessionCache.get(u2)); // undefined - ок!
    console.log(sessionCache.size); // 1
    

    Преимущества Map для кэша сессий:

    • Ключи любого типа: объекты, функции, Date.
    • .has(key), .delete(key) - O(1) без Object.keys().
    • Итераторы keys(), values(), entries() - чище Object.entries().
    Свойство Object Map
    Ключи строки/Symbol любой тип
    Размер Object.keys().length .size
    Get/Set obj[key] .get/.set
    Итерация for…in (прототип!) for…of чисто
    Кэш сессий коллизии [object Object] ссылки OK

    WeakMap для сессий без утечек памяти

    Обычный Map держит ключи сильно, объект-ключ не удалится GC пока Map жив. Для сессий - WeakMap: ключи слабо ссылаются, память чистится автоматически при удалении userObj.

    В бэкенде/фронте: хранишь сессию по DOM-элементу или Worker’у как ключ. Когда элемент удален - сессия уходит без .delete. Идеально для временного кэша без ручной уборки.

    Практика:

    const sessionWeakCache = new WeakMap();
    const userObj = {id: 1};
    sessionWeakCache.set(userObj, 'session data');
    console.log(sessionWeakCache.get(userObj)); // 'session data'
    // userObj = null; // ключ удалится GC
    

    Когда WeakMap рулит:

    • Ключи - DOM-ноды, объекты от API без ID.
    • Нет .size, .keys() - только get/set/has/delete.
    • Нет сериализации в JSON - только для runtime кэша.

    Подводный камень: WeakMap не итерируется, нельзя Object.fromEntries(map).

    Фиксим legacy-код: от Object к Map

    В старом коде cache на Object. Миграция: new Map(Object.entries(cacheOld)), но только если ключи строковые! Для объектных - рефактори ключ на stringId или Symbol.

    Гибрид: публичный API оставь Object, внутри Map. Конвертируй через Object.fromEntries(map.entries()) - но проверяй ключи на объекты.

    Шаги рефакторинга:

    1. Замени const cache = {} на new Map().
    2. .set(key, val) вместо cache[key] = val.
    3. .get(key) вместо cache[key]. Добавь || default.
    4. Для JSON - Object.fromEntries(cache).

    Антипаттерны избегать:

    • JSON.stringify(key) как хэш - коллизии по содержимому.
    • Массивы как ключи в Object - то же [object Array].
    • Глобальный cache без WeakMap - утечки памяти.

    Под капотом еще есть грабли

    Object прототип наследуется, Map чистый. В Object for…in ловит Object.prototype - фильтруй hasOwnProperty. Map итерируется только свои записи.

    Осталось: производительность на 10k+ элементов (Map быстрее), полифиллы для старых браузеров. Подумай, стоит ли WeakRef в связке с Map для продвинутого GC в сессиях - там свои подводные камни с timing’ом очистки.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: 79% положительных в Steam, но туториалы отпугивают игроков

    Обложка: Pathologic 3: 79% положительных отзывов в Steam и почему туториалы отпугивают игроков

    Pathologic 3 вышла 9 января на PC и PS5, набрав 79% положительных отзывов в Steam по 146 рецензиям за последние 30 дней. Пиковый онлайн - 3077 человек в сутки, что вдвое больше рекорда второй части.

    Игра занимает топ-10 лидеров продаж Steam, обходя Dota 2 и PUBG, со скидкой 20% до 23 января - 960 рублей. Это успех для нишевого психологического хоррора от Ice-Pick Lodge, но критика туториалов портит старт новичкам. Почему это важно: серия всегда была хардкорной, но теперь барьер входа отпугивает часть аудитории.

    Отзывы и статистика

    Pathologic 3 - психологический хоррор, где врач борется с эпидемией в городе за 12 дней. Механика включает манипуляцию временем, точные диагнозы и жесткие решения, меняющие судьбы жителей.

    В Steam рейтинг “в основном положительные” - 79% из 146 обзоров за месяц. Ранее на старте было 87% по 370 рецензиям, но цифры просели. В PS Store - 4.6/5, но всего <50 отзывов. Metacritic - 79 баллов.

    Положительные отзывы хвалят:

    • Мрачную атмосферу и смелые изменения по сравнению со второй частью.
    • Сценарий, юмор и уважение к интеллекту игрока.
    • Пиковый онлайн 3077 - прорыв для франшизы.

    Отрицательные - от ветеранов первой и второй частей, недовольных изменениями.

    Проблема с туториалами

    Туториалы в Pathologic 3 вызывают основной негатив у новичков. Серия всегда славилась отсутствием руки-помощника, но здесь инструкции сбивчивые и мешают погружению.

    Игроки жалуются, что туториалы:

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

    Это отпугивает casual-аудиторию, которая пришла за хайпом. Ветераны терпят, но для них серия - про самопознание через хаос, без подсказок.

    Что дальше для игроков

    Релиз на Xbox Series - 23 января. Kickstarter-бэкеры получат игру бесплатно. Механика жесткая: частые смерти исчерпывают ресурсы, сохранения удаляются - переигрывай с нуля.

    Для игроков последствия:

    • Покупать сейчас? Со скидкой - да, если готов к хардкору. Атмосфера тащит, но туториалы сломают первый час.
    • Ждать патча? Разрабы молчат о фиксах, но отзывы давят - изменения возможны.
    • Сравнение с прошлыми частями - онлайн в 2 раза выше, продажи топ, но ветераны спорят о “душе” серии.

    Xbox-версия протестирует стабильность на консолях.

    Итог

    Pathologic 3 подтверждает статус франшизы - нишевый хит с барьерами. 79% в Steam - солидно, но туториалы рискуют потерять новичков. Успех продаж показывает интерес, но серия останется для тех, кто ценит вызов без компромиссов.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Flutter и Kotlin Multiplatform для экзотических платформ: от Авроры до продакшена

    Представьте: клиент требует приложение не только под Android и iOS, но и под российскую Аврору ОС, HarmonyOS или даже embedded-системы на заводах. Две команды разработчиков? Двойной бюджет и сроки? Забудьте. Flutter и Kotlin Multiplatform позволяют писать код один раз и запускать на всем, от смартфонов до смарт-часов и Linux-терминалов. Это решает главную боль бизнеса: экономия до 60% на разработке без потери производительности.

    Flutter рисует UI сам через Skia, обеспечивая 60 FPS везде одинаково. Kotlin Multiplatform делит бизнес-логику, оставляя нативный интерфейс для каждой платформы. В 2026 оба зрелы: KMP стабилен с 2023, Flutter доминирует с 46% рынка.

    Почему экзотические платформы ждут именно их?

    Аврора ОС (российский аналог Android) официально поддерживается Flutter через Linux-бэкенд. Собираете APK/AAB и деплоите на устройства МВД или госкомпаний. Kotlin Multiplatform тоже работает: shared-модуль на Kotlin компилируется в нативный код для Aurora.

    HarmonyOS от Huawei? Flutter имеет экспериментальную поддержку через HarmonyOS NEXT SDK. KMP интегрируется с ArkTS, используя Kotlin как основу для логики.

    Linux-терминалы, Raspberry Pi или промышленные HMI? Flutter на Linux desktop собирается в единый бинарник. KMP с Compose Multiplatform рендерит нативный UI на Wayland/X11.

    Платформа Flutter Kotlin Multiplatform
    Аврора ОС Полная (Linux backend) Shared logic + native UI
    HarmonyOS Экспериментальная Через ArkTS
    Linux/Embedded Desktop + ARM Compose + JVM
    Производительность 60 FPS, Skia Нативная, без движка
    Размер APK 15-25 MB Меньше на 4-10 MB

    Flutter выигрывает в скорости прототипирования: hot reload меняет UI за секунды. KMP - в гибкости: делите только логику, UI пишете на SwiftUI/Jetpack Compose.

    Практика: быстрый shared модуль на Kotlin Multiplatform

    Для экзотических платформ пишем общую логику аутентификации. Вот базовый пример KMP-модуля (expect/actual):

    // commonMain/kotlin/com/example/SharedAuth.kt
    expect class AuthManager {
        fun login(username: String, password: String): Result<String>
    }
    
    // androidMain/kotlin/com/example/PlatformAuth.kt
    actual class AuthManager {
        actual fun login(username: String, password: String): Result<String> {
            // Android impl with Retrofit
            return runBlocking { /* API call */ }
        }
    }
    
    // iosMain/kotlin/com/example/PlatformAuth.kt
    actual class AuthManager {
        actual fun login(username: String, password: String): Result<String> {
            // iOS impl with URLSession
        }
    }
    

    Интегрируете в Flutter через FFI или используете в чистом KMP-проекте. Для Авроры actual-блок на JVM остается тем же. Тестируйте на эмуляторе - профит в переиспользовании 80% кода.

    Flutter проще для UI: один виджет TreeShake’ится под платформу. Но если нужен пиксель-перфект натив (типа Material3 на Android), KMP с Compose предпочтительнее.

    Flutter vs KMP: когда что брать в прод?

    Flutter для MVP и UI-heavy apps: Netflix тестирует на embedded, Philips на смарт-TV. Экономия бюджета до 60%, разработка в 40% быстрее. Минус: размер APK больше из-за Skia.

    KMP для enterprise: VMware, Forbes на критичных системах. Нативная производительность, прямой доступ к API (Bluetooth на embedded без bridges). Google пушит совместимость с 2024.

    В РФ Аврора и Astra Linux толкают импортозамещение. Flutter уже в госзаказах (меньше зависимостей), KMP растет на 23% рынка за счет Java-команд. Оба подходят, но KMP стабильнее для legacy.

    Для автоматизации деплоя на экзотические платформы использую CI/CD на GitHub Actions:

    # .github/workflows/deploy.yml
    name: Deploy KMP
    on: [push]
    jobs:
      aurora:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: Build Aurora
            run: ./gradlew assembleAuroraRelease
          - name: Upload
            uses: actions/upload-artifact@v4
            with:
              name: aurora-apk
              path: app/build/outputs/apk/aurora/release/
    

    Запускайте на пуш - артефакты для всех платформ автоматически.

    Итог: что выгнали в бой?

    Flutter - для быстрого захвата рынка с единым UI. KMP - для надежного продакшена с нативом. В 2026 комбинируйте: Flutter UI + KMP logic через FFI. Бизнес профит: один код, много платформ, меньше devops.

    А вы уже пробовали запускать на Авроре или Harmony? Какой стек юзаете для embedded и сколько сэкономили? Делитесь в комментах - обсудим реальные кейсы!


    0 0 0 Ответить
  • hannadevH
    hannadev
    Map vs Object: коллизии ключей и баги кэша настроек пользователя

    Object в JavaScript сливает ключи в коллизию, потому что всегда приводит их к строкам. Map держит типы как есть - это спасает от багов в кэше пользовательских настроек. Разберём, почему это происходит и как избежать типичных граблей.

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

    Как Object ломает ключи под капотом

    Object - это хеш-таблица с примитивным хешем: любой ключ toString()ится в строку. Число 1 и строка ‘1’ станут одним ключом, объект превратится в ‘[object Object]’. Это не баг, это фича ECMAScript - прототипы и унаследованные свойства так работают десятилетиями.

    Представь кэш настроек: юзер выбирает id=1 (число) для темы, потом api кидает ‘1’ (строка). Object перезапишет значение, и тема слетит. А Map сохранит оба как разные ключи. Производительность тоже страдает: Object.keys() пересчитывает каждый раз, map.size - O(1).

    Вот классический пример коллизии:

    • obj= ‘тёмная тема’ - ключ станет строкой ‘1’
    • obj[‘1’] = ‘светлая тема’ - перезапишет предыдущее
    • map.set(1, ‘тёмная’), map.set(‘1’, ‘светлая’) - size будет 2
    Свойство Object Map
    Типы ключей Только строки/Symbol Любые: число, объект, функция
    Размер Object.keys().length (O(n)) .size (O(1))
    Итерация Object.entries() for…of напрямую
    JSON JSON.stringify работает Нужно fromEntries()

    Нюанс: не путай map[key] = value с map.set(key, value) - первое ведёт себя как Object.

    Коллизии в кэше настроек: реальные грабли

    Кэш настроек часто хранит userId как число из localStorage, но api возвращает строку. Object сольёт их, и настройки подменятся. Ещё хуже с объектами: два разных {theme: ‘dark’} станут одним ‘[object Object]’ - все юзеры увидят чужие prefs.

    В легаси-коде это маскируется: Object.assign или spread, но под нагрузкой лезут утечки. Map не даёт прототипу вмешиваться, has/get/delete - чистые O(1). Для кэша с частыми set/delete Map выигрывает, Object хорош только для статичного конфига.

    Типичные баги в кэше:

    • Перезапись по числу/строке: userSettings vs userSettings[‘123’]
    • Объекты как ключи: два formData сливаются в одну строку
    • Динамические ключи от юзера: input.value (строка) vs parseInt(id) (число)
    • Итерация: for…in ловит прототип, Map чистая
    Сценарий кэша Object (риск коллизии) Map (безопасно)
    userId число/строка Высокий - сливает Низкий - разные ключи
    Объект как ключ 100% ‘[object Object]’ Ссылка сохраняется
    Частые обновления Деградация на delete Стабильный O(1)
    Сериализация Легко Object.fromEntries(map)

    Важно: для >64K ключей Object может быть быстрее чистого чтения, но редко в настройках.

    Когда Map - твой спаситель в продакшене

    Выбирай Map для динамического кэша: user prefs, session data, A/B тесты. Object оставь для статичного: CSS vars, env config. В React/Vue хуки с useCallback объектами как ключами - чистая замена Map, без лишних ререндеров.

    Под капотом Map - настоящая хеш-таблица с цепочками для коллизий, Object - упрощённая с toString хешем. В V8 Map оптимизирована для mixed workloads, Object - для строковых. Тестировал: на 10K set/get Map в 1.5x быстрее при удалениях.

    Правила миграции с Object на Map:

    1. new Map(Object.entries(oldObj)) - быстрая конверсия
    2. Object.fromEntries(map.entries()) - обратно, но проверь ключи на строковость
    3. clear() перед refill - избегай утечек памяти
    4. Итерация: for (const [k,v] of map) - порядок вставки сохранён
    const cache = new Map();
    cache.set(userId, settings); // userId может быть чем угодно
    if (cache.has(userId)) { /* hit */ }
    

    Нюанс: Map не WeakMap - держит сильные ссылки, для GC юзай WeakMap с объектами.

    Хеш-механика: почему коллизии неминуемы

    Хеш-функция берёт ключ, хешит в индекс массива. Размер таблицы конечен, коллизии - когда разные ключи в один слот. Object решает цепочками, но toString упрощает до абсурда. Map использует SameValueZero - строже ===.

    В кэше настроек юзер может закинуть NaN, +0/-0, undefined - Object их сольёт, Map разнесёт. Для перфоманса: до 4K ключей Map идеальна, дальше мониторь. Но в типичном app настроек <1K - профит чисто.

    Стратегии избежания:

    • Нормализуй ключи заранее: всегда toString() для Object
    • Map по дефолту для user data
    • WeakMap для temp объектов
    • Тестируй: benchmark set/get/delete на твоём workload
    Метод разрешения Object Map
    Коллизия ключей toString() Хеш + SameValueZero
    Объекты ‘[object Object]’ === ссылка
    NaN как ключ ‘NaN’ Единственный NaN

    Подводный камень: JSON.stringify(map) даст {}, конвертируй entries.

    Бэкdoor в архитектуре: hybrid подход

    Не всегда full Map - иногда hybrid: статичный config в Object, динамика в Map. Или Proxy на Object с weak кэшем. Но рефактори ruthlessly: если баги от коллизий - мигрируй целиком.

    Осталось за кадром: под капотом V8 SpiderMonkey, где Map уступает на pure read heavy. Подумай над своим стеком - localStorage? IndexedDB? Там тоже коллизии ждут. И всегда профайлер в руки перед выбором.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: 87% положительных отзывов, но баги и упрощения взорвали форумы

    Обложка: Pathologic 3: первые отзывы игроков после релиза и почему баги уже взорвали форумы

    Pathologic 3 вышла вчера на PC и PS5, и Steam уже показывает 87% положительных отзывов. Большинство хвалит атмосферу, диалоги и сюжет, но фанаты старых частей в ярости от багов и потери хардкора.

    Игра собрала около 3 тысяч одновременных игроков в первый день. Сейчас со скидкой 20% стоит 960 рублей, бэкеры Kickstarter получат бесплатно. Проблемы с фризами и геймплеем уже заполонили обсуждения - от ругани на механики до восторгов новичков.

    Отзывы: восторг и разочарование

    Pathologic 3 - это психологический хоррор от Ice-Pick Lodge про врача Даниила Данковского, который пытается спасти чумной город за 12 дней. Нелинейный сюжет, моральные выборы и давление времени остались фирменными чертами серии.

    Большинство игроков в Steam отмечает сильные стороны:

    • Живые диалоги и многогранные персонажи.
    • Атмосфера провинциального кошмара.
    • Хорошая оптимизация для большинства систем.

    Рейтинг держится на 85-87% положительных. Но старожилы первого и второго “Мора” ругают изменения. Критикуют “лень” разработчиков: перемещение стало проще, опасные районы не такие рискованные, геймплей дружелюбнее хардкора предшественников.

    Баги: что бесит игроков

    Форумы и отзывы Steam кипят от технических проблем. Фризы во вступительном ролике - главная жалоба, особенно у части пользователей. Игра получилась забагованной, с глюками, которые мешают погружению.

    Кто-то сравнивает с квестом - мол, потеряла выживачку, стала линейнее. Гневные посты сосредоточены на:

    • Новой механике движения, которую зовут слишком простой.
    • Отсутствии высоких рисков в зонах.
    • Общем упрощении по сравнению с классикой.

    Журналисты дают теплые рецензии, хвалят артхаус и эмоции. Но игрокам это не катит - баги реально портят старт.

    Что дальше для игроков

    Xbox Series ждут 23 января. Владельцы Pathologic 2 или Classic HD имеют допскидку 15%. Если баги пофиксят патчем - рейтинг взлетит, как у прошлых частей студии.

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

    Итог ожиданий

    Pathologic 3 вышла неоднозначной: 87% хвалы против багов и споров о хардкоре. Ice-Pick Lodge держит планку артхауса, но технические огрехи и упрощения раздражают ветеранов. Следите за патчами - они решат судьбу рейтинга.


    0 0 0 Ответить
  • hannadevH
    hannadev
    validity.state вместо if-ов: браузер валидирует формы на лету без костылей

    Устал от кучи if-else в обработчиках форм? Браузер уже всё проверит сам через validity.state. Это объект с флагами ошибок, который обновляется на лету без твоего JS.

    Забудь ручные проверки на пустоту, длину или паттерны. Атрибуты HTML типа required, minlength, pattern сами генерируют состояния :valid и :invalid. Получаешь чистый код, меньше багов и ноль зависимостей. Разберём, как это работает под капотом и почему мидлы всё равно пишут костыли.

    Как validity.state ловит ошибки без твоего кода

    Браузерный движок следит за каждым вводом и обновляет validity - объект с булевыми флагами. Там valueMissing для required, tooShort для minlength, patternMismatch для regex. Всё это живое: ввёл букву - флаг переключился.

    Не нужно oninput с if (value.length < 5). Браузер сам решает, валидно или нет, и вешает :invalid. Плюс checkValidity() вернёт true/false для всей формы. А setCustomValidity() позволит подправить сообщение, если надо кастом.

    Это решает типичные грабли: утечки в ивент-лупе от лишних слушателей, несинхронные проверки при submit. Вместо 50 строк JS - пара атрибутов в HTML.

    • valueMissing: true, если required-поле пустое. Браузер блочит submit.
    • typeMismatch: для email/number - ввёл буквы в цифры? Флаг взлетел.
    • tooLong/tooShort: min/maxlength сами считают символы, без твоих счётчиков.
    • patternMismatch: regex в pattern атрибуте - браузер парсит нативно.
    • valid: итоговый флаг. true только если все остальные false.
    Состояние Псевдокласс Пример атрибута Что блочит
    Пустое required :invalid required submit
    Короткий текст :invalid minlength=“5” флаг tooShort
    Не email :invalid type=“email” typeMismatch
    Соответствует :valid pattern=“[a-z]+” submit OK

    Подключаем CSS для состояний: стили без JS

    Псевдоклассы :valid и :invalid - это готовый API для стилей. input:invalid { border: 2px solid red; } - и поле краснеет на лету. Добавь :required для фокуса на обязательных.

    form:invalid блокирует кнопку: button[type=submit] { opacity: 0.5; pointer-events: none; } form:valid button { opacity: 1; pointer-events: auto; }. Никаких MutationObserver или ResizeObserver - чистый CSS.

    Новички пишут onblur с классами error/success, но это бандл разрастается. Браузер уже знает состояние, зачем дублировать? Минус один слушатель на поле.

    • input:invalid: красная обводка + shake-анимация для фидбека.
    • input:valid + input:focus:valid: зелёный чекмарк через ::after.
    • form:invalid ~ button: disable до полной валидности формы.
    • :out-of-range: для number min/max - стилизуй отдельно.
    input:invalid {
      border-color: #e74c3c;
      animation: shake 0.5s;
    }
    
    input:valid {
      border-color: #27ae60;
    }
    
    form:invalid button {
      background: #bdc3c7;
      cursor: not-allowed;
    }
    

    JS только для тонкой настройки: checkValidity и кастом

    Хочешь свои сообщения? validity.validationMessage - стоковое от браузера. Перезапиши через setCustomValidity(‘Минимум 8 символов, бро’). Вызывай в oninput или после debounce.

    reportValidity() покажет все ошибки диалогом - браузер сам. Для a11y: aria-invalid=“true” на invalid полях, aria-errormessage ссылается на спан с текстом.

    Без JS форма валидна по дефолту, но мидлы добавляют preventDefault и циклы по полям. validity.state избавляет от этого: if (!form.checkValidity()) return; - и всё.

    • reportValidity(): браузерный popup со всеми ошибками.
    • setCustomValidity(‘’): сбрасывает кастом, возвращает к нативному.
    • aria-invalid связывается с validity.valid автоматически в новых браузерах.
    • CustomError: validity.customError для твоих флагов.
    Метод Что делает Когда юзать
    checkValidity() true/false для поля/формы перед submit
    reportValidity() Показывает ошибки UI onsubmit fallback
    setCustomValidity() Кастом текст ошибки после async чека

    Грабли с validity, которые бьют мидлов

    Не все флаги работают везде: customError игнорирует :invalid, пока не вызовешь checkValidity. pattern на type=search может глючить в старых Safari.

    willValidate false для disabled/readonly - браузер пропускает. rangeUnderflow/Overflow для number - забудь про ручной парсинг Int.

    Мидлы пишут глобальные валидаторы с Lodash, но validity.state - 0kb, нативно. Тестируй: console.log(input.validity) - увидишь все флаги живьём.

    • rangeOverflow: > max в number - браузер ловит.
    • stepMismatch: не кратно step в range.
    • validLength: false при mismatch min/maxlength.

    Нативка рулит, но кастом всё равно нужен

    validity.state - идеал для 80% форм: регистрация, поиск, фильтры. JS только для серверного чека или сложных правил типа уникальности email.

    Осталось async: подожди API, потом setCustomValidity на основе ответа. Или polyfill для IE, но кто его юзает в 2026? Думай о производительности: меньше JS - быстрее ивент-луп.


    0 0 0 Ответить
Популярные темы:

  • Критическая уязвимость в React.js Next.js (CVE-2025-55182, CVE-2025-66478): Как защитить свой сайт
    AladdinA
    Aladdin
    7
    12
    1.2k

  • Полный гайд по работе с NodeBB CLI
    D
    DeepSeeker
    6
    3
    157

  • for или foreach в javascript: в каких случаях что использовать
    D
    DeepSeeker
    5
    2
    164

  • Подготовка к собесам фронтенд
    Dastan SalmurzaevD
    Dastan Salmurzaev
    5
    5
    199

  • Передача типов в TypeScript в под функции
    kirilljsxK
    kirilljsx
    4
    5
    226

  • Исчерпывающее руководство по конфигурации Nginx
    undefined
    4
    1
    228

  • Проверка стала проще с Zod: как обеспечить точность и качество форм
    kirilljsxK
    kirilljsx
    3
    8
    1.1k

  • Bruno - новый клиент для API (Замена PostMan Insomnia)
    ManulM
    Manul
    3
    2
    1.8k

  • Vue.js и React — необычное сравнение
    D
    DeepSeeker
    3
    10
    1.1k

  • Оптимизация React js приложений. Использование функции debounde()
    ManulM
    Manul
    3
    5
    544

  • Провайдеры в Nest JS - 1.3
    undefined
    3
    1
    363

  • Полный гайд по команде LFTP: Работа с локальными и удалёнными серверами
    undefined
    3
    1
    662

Пользователи в Сети:

Статистика:

70

В сети

328

Пользователи

2.0k

Темы

2.9k

Сообщения

Категории

  • Главная
  • Новости
  • Фронтенд
  • Бекенд
  • Языки программирования

Контакты

  • Сотрудничество
  • info@exlends.com

© 2024 - 2026 ExLends, Inc. Все права защищены.

Политика конфиденциальности
  • Войти

  • Нет учётной записи? Зарегистрироваться

  • Войдите или зарегистрируйтесь для поиска.
  • Первое сообщение
    Последнее сообщение
0
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы