Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Языки программирования
  4. JavaScript
  5. Map.getOrInsert в ECMAScript 2026: атомарные операции для Map

Map.getOrInsert в ECMAScript 2026: атомарные операции для Map

Запланировано Прикреплена Закрыта Перенесена JavaScript
mapecmascript 2026javascript
1 Сообщения 1 Постеры 0 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • hannadevH В сети
    hannadevH В сети
    hannadev
    написал отредактировано
    #1

    Недавно в ECMAScript 2026 добавили два новых метода для работы с Map и WeakMap - getOrInsert и getOrInsertComputed. Это не просто очередное расширение API, а решение реальной проблемы, с которой сталкиваются разработчики каждый день. Методы упрощают код, делают его понятнее и избавляют от лишних проверок.

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

    Проблема, которую решают новые методы

    Представьте, что вам нужно собрать данные по группам. Например, у вас есть список продаж, и вы хотите сгруппировать их по категориям. До появления getOrInsert код выглядел вот так:

    let grouped = new Map();
    for (let [key, ...values] of data) {
      if (grouped.has(key)) {
        grouped.get(key).push(...values);
      } else {
        grouped.set(key, values);
      }
    }
    

    Видите, как много здесь проверок? Сначала смотрим has(), потом get(), потом set(). Код не сложный, но его приходится писать снова и снова. Это похоже на ситуацию с Java и методами computeIfAbsent - разработчики годами просили что-то подобное.

    Основные неудобства старого подхода:

    • Нужно писать три операции вместо одной (has, get, set)
    • Код выглядит многословным и нарушает DRY-принцип
    • Легко сделать ошибку или забыть одну из проверок
    • Ключ проверяется дважды - при has() и при get()
    • В Map выполняется несколько поисков вместо одного

    getOrInsert - простое и понятное решение

    Теперь с getOrInsert то же самое выглядит намного чище:

    let grouped = new Map();
    for (let [key, ...values] of data) {
      grouped.getOrInsert(key, []).push(...values);
    }
    

    Одна строка вместо четырёх! Метод работает очень просто: если ключ уже есть в Map, он возвращает существующее значение. Если нет - вставляет новое значение и возвращает его. В обоих случаях вы получаете значение, с которым можете работать дальше.

    Как работает getOrInsert:

    • Проверяет наличие ключа в Map
    • Если ключ найден - возвращает его значение
    • Если ключа нет - устанавливает переданное значение как дефолт
    • Возвращает значение в любом случае
    • Всё это происходит как одна атомарная операция

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

    getOrInsertComputed - когда дефолт вычисляется дорого

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

    Для этого есть getOrInsertComputed. Вместо готового значения вы передаёте функцию, которая будет вызвана только если ключа нет в Map:

    let grouped = new Map();
    for (let [key, ...values] of data) {
      grouped.getOrInsertComputed(key, () => []).push(...values);
    }
    

    Отличие в деталях: вы передаёте стрелочную функцию вместо готового массива. Эта функция вызывается только если ключа нет. Если ключ уже существует - функция не выполняется вообще.

    Когда это особенно полезно:

    • Когда дефолтное значение требует вычислений или I/O операций
    • Для ленивой инициализации сложных структур данных
    • При работе с кешами или кэшированием значений
    • Когда создание значения может быть дорогостоящим процессом
    • В случаях, когда значение зависит от внешнего состояния

    Кроме того, getOrInsertComputed работает с WeakMap тем же способом - вы получаете одну операцию вместо нескольких проверок.

    Сравнение подходов

    Подход Готовое значение Ленивое вычисление Использование Производительность
    Старый способ (has/get/set) ✓ Нет встроенного способа Везде Несколько поисков в таблице
    getOrInsert() ✓ ✗ Простые значения Один поиск в таблице
    getOrInsertComputed() ✗ ✓ Дорогие вычисления Один поиск + условное вычисление

    Видите разницу? Новые методы заменяют целый паттерн кода, который раньше требовал либо множества строк, либо обёрток в функции. Это как перейти с для цикла на forEach - удобнее, понятнее и безопаснее.

    Практические примеры использования

    Давайте посмотрим, где эти методы особенно помогают. Первый пример - счётчик событий:

    const eventCounts = new Map();
    
    function logEvent(eventName) {
      const count = eventCounts.getOrInsert(eventName, 0);
      eventCounts.set(eventName, count + 1);
    }
    

    Здесь getOrInsert гарантирует, что вы всегда получите число, даже если это первое событие.

    Второй пример - кэш с ленивой инициализацией:

    const userCache = new WeakMap();
    
    function getUserData(user) {
      return userCache.getOrInsertComputed(user, () => {
        // Это выполнится только если user не в кэше
        return fetchUserDataFromDatabase(user);
      });
    }
    

    Здесь вы не тратите ресурсы на запросы к базе для пользователей, которые уже в кэше.

    Третий пример - построение индекса данных:

    const index = new Map();
    
    for (const item of items) {
      const bucket = index.getOrInsert(item.type, () => []);
      bucket.push(item);
    }
    

    Это очень чистый и понятный способ сгруппировать элементы по типам.

    Реальные сценарии применения:

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

    Совместимость и поддержка браузерами

    ЭТИ методы уже включены в ECMAScript 2026, что означает, что браузеры и рантаймы начнут поддерживать их прямо сейчас. Chrome уже добавил поддержку, и другие движки последуют вскоре.

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

    Сроки поддержки:

    • ECMAScript 2026 спецификация: уже финализирована
    • Chrome и Chromium: поддержка начата
    • Firefox: поддержка планируется
    • Safari: поддержка планируется
    • Node.js: будет добавлена в ближайших версиях

    Если вы работаете с TypeScript, типы для этих методов уже включены в свежие версии типов DOM и ECMAScript.

    Атомарность операций

    Одно из ключевых достоинств этих методов - они выполняются как единая операция. Это важно, потому что код становится проще и понятнее. Вы не рискуете потерять данные между проверкой и устанавливанием значения, если что-то пойдёт не так.

    Хотя JavaScript однопоточный, поэтому race conditions из многопоточных языков здесь невозможны, эти методы всё равно полезны. Они гарантируют, что логика “получи или создай” выполнится как единое целое, без промежуточных состояний.

    Почему это важно:

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

    Родство с методами других языков

    Это не новая идея - похожие методы уже давно существуют в других языках. Java имеет computeIfAbsent и computeIfPresent, Scala предлагает getOrElseUpdate. Теперь JavaScript наконец-то ловит поезд.

    Но JavaScript выбрал собственный путь, создав два метода вместо одного. getOrInsert работает с готовыми значениями, а getOrInsertComputed - с функциями. Это разделение ответственности делает API чище и проще в понимании.

    Когда вы видите getOrInsert, вы сразу знаете, что тут просто передача готового значения. А getOrInsertComputed - это лениво вычисляемое значение. Нет размытости в коде.

    Что дальше?

    Эти методы - результат многолетних дискуссий в сообществе разработчиков. Предложение начиналось с GitHub, обсуждалось в TC39, и теперь стало частью стандарта. Это показывает, как работает процесс эволюции JavaScript.

    Ваша задача как разработчика - начать использовать эти методы в своих проектах, когда это имеет смысл. Они не волшебная палочка, но для работы с Map и WeakMap это явный шаг вперёд. Код становится понятнее, короче и менее подвержен ошибкам. А это всегда хорошо.

    1 ответ Последний ответ
    0

    Категории

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

    Контакты

    • Сотрудничество
    • info@exlends.com
    • Наш чат
    • Наш ТГ канал

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

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

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

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