Avatar ·

Как создать GUID / UUID в JavaScript?

Всем привет! Я пишу небольшое веб-приложение на чистом JavaScript, и мне нужно генерировать уникальные идентификаторы для разных сущностей (например, для задач в списке дел или для записей в локальном хранилище). Я знаю, что в других языках (Python, C#) есть встроенные функции для создания GUID/UUID, но в JavaScript я не нашёл ничего подобного. Проблема в том, что я не хочу использовать простые счётчики типа `let id = 0; id++`, потому что при перезагрузке страницы счётчик сбрасывается, а если приложение будет работать с несколькими вкладками или с сервером, могут возникнуть коллизии. Я пробовал написать свою функцию на основе `Math.random()`, но читал, что это небезопасно и не гарантирует уникальность. Вот что у меня получилось: ```javascript function generateId() { return Math.random().toString(36).substr(2, 9); } ``` Это работает, но я боюсь, что в какой-то момент могут появиться дубликаты, особенно если генерировать много ID подряд. Подскажите, пожалуйста, как правильно и надёжно создавать UUID/GUID в JavaScript? Хотелось бы увидеть примеры с пояснением, чтобы я понимал, как это работает. Заранее спасибо! <<>>

Стандартное решение: метод crypto.randomUUID()

Начиная с 2022 года, в современном JavaScript появился встроенный метод для генерации UUID версии 4 (случайный UUID). Он доступен через глобальный объект crypto, который есть во всех современных браузерах и Node.js 19+. Это самый правильный и безопасный способ.

const uuid = crypto.randomUUID();
console.log(uuid); // Пример: "f47ac10b-58cc-4372-a567-0e02b2c3d479"

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

Метод crypto.randomUUID() генерирует UUID версии 4 (RFC 4122). Он использует криптостойкий генератор случайных чисел (crypto.getRandomValues()), что гарантирует:

  • Уникальность — вероятность коллизии ничтожно мала (около 5.3 × 10⁻³⁶ для 122 бит случайных данных).
  • Безопасность — невосприимчив к атакам, основанным на предсказании случайных чисел.
  • Стандартный формат — возвращает строку вида xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, где 4 — версия UUID, а y — вариант (8, 9, a или b).

Формат UUID v4

UUID состоит из 32 шестнадцатеричных цифр, разделённых дефисами на 5 групп: 8-4-4-4-12. В версии 4:

  • 13-й символ всегда 4 (указывает версию).
  • 17-й символ — один из 8, 9, a, b (указывает вариант).
  • Остальные 122 бита — случайные.

Полифилл для старых браузеров / Node.js

Если нужно поддерживать старые окружения, можно использовать crypto.getRandomValues() напрямую:

function generateUUID() {
    const chars = '0123456789abcdef';
    const randomValues = new Uint8Array(16);
    crypto.getRandomValues(randomValues);
    
    // Устанавливаем версию (4) и вариант (8, 9, a, b)
    randomValues[6] = (randomValues[6] & 0x0f) | 0x40; // Версия 4
    randomValues[8] = (randomValues[8] & 0x3f) | 0x80; // Вариант
    
    let uuid = '';
    for (let i = 0; i < 16; i++) {
        if (i === 4 || i === 6 || i === 8 || i === 10) {
            uuid += '-';
        }
        uuid += chars[randomValues[i] >> 4] + chars[randomValues[i] & 0x0f];
    }
    return uuid;
}

console.log(generateUUID()); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"

Почему не стоит использовать Math.random()?

Хотя Math.random() даёт псевдослучайные числа, он:

  • Не является криптостойким — его можно предсказать.
  • Имеет ограниченную энтропию (около 52 бит против 122 бит в UUID v4).
  • Может давать коллизии при большом количестве генераций (парадокс дней рождения).

Использование в Node.js

В Node.js 19+ метод доступен напрямую. Для более старых версий используйте модуль uuid:

npm install uuid
const { v4: uuidv4 } = require('uuid');
console.log(uuidv4()); // "f47ac10b-58cc-4372-a567-0e02b2c3d479"

Когда использовать UUID?

  • Базы данных — как первичный ключ (особенно в распределённых системах).
  • Клиент-серверное взаимодействие — для идентификации запросов/сессий.
  • Локальное хранилище — для уникальных ID объектов (задачи, заметки).
  • URL-идентификаторы — если нужно скрыть порядковый номер (например, /user/f47ac10b-58cc-4372-a567-0e02b2c3d479).

Вывод: Используйте crypto.randomUUID() — это современный, безопасный и стандартизированный способ. Если нужна поддержка старых браузеров — используйте полифилл на основе crypto.getRandomValues().

<<>>

Альтернативный подход: библиотека nanoid

Если вам не нужна полная совместимость со стандартом UUID, а требуется просто компактный и быстрый уникальный идентификатор, обратите внимание на библиотеку nanoid. Она генерирует более короткие ID (по умолчанию 21 символ), но с той же степенью уникальности.

// Установка: npm install nanoid
import { nanoid } from 'nanoid';

const id = nanoid(); // "V1StGXR8_Z5jdHi6B-myT"
console.log(id); // 21 символ

Преимущества nanoid

  • Компактность — ID короче UUID (21 символ против 36).
  • Скорость — в 2-3 раза быстрее генерации UUID.
  • Настраиваемость — можно изменить длину и алфавит.
  • Безопасность — использует crypto.getRandomValues().
// Свой алфавит и длина
const customNanoid = nanoid.customAlphabet('1234567890abcdef', 10);
console.log(customNanoid()); // "a3f8b2c1d0"

Когда выбирать nanoid вместо UUID?

  • Нужны короткие URL или читаемые ID.
  • Не требуется строгое соответствие стандарту UUID.
  • Важна производительность (например, в циклах с тысячами генераций).

Однако помните: если ваша система должна взаимодействовать с другими системами, ожидающими формат UUID, лучше использовать crypto.randomUUID().