README.ru.md
English | 日本語 | Русский | 简体中文 | Bahasa Indonesia | 한국어 | العربية
Генератор уникальных ID для JavaScript — лёгкий, безопасный, ID можно применять в URL.
«Поразительный уровень бессмысленного перфекционизма, который просто невозможно не уважать»
A-Za-z0-9_-).
Поэтому длина ID уменьшена с 36 до 21 символа.import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
Поддерживает современные браузеры, IE (с Babel), Node.js и React Native.
Сделано в <b><a href="https://evilmartians.com/devtools?utm_source=nanoid&utm_campaign=devtools-button&utm_medium=github">Злых марсианах</a></b>, продуктовом консалтинге для <b>инструментов разработки</b>.
Nano ID похож на UUID v4 (случайный). У них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID), поэтому они обладают похожей вероятностью возникновения коллизий (повторной генерации ранее выданных ID):
Чтобы вероятность повтора приблизилась к 1 на миллиард, нужно сгенерировать 103 триллиона ID.
Но между ними есть 2 важных отличия:
uuid/v4 — 118 байт против 423.$ node ./test/benchmark.js
crypto.randomUUID 21,741,317 ops/sec
uuid v4 21,204,378 ops/sec
@napi-rs/uuid 10,236,615 ops/sec
uid/secure 10,567,676 ops/sec
@lukeed/uuid 8,647,481 ops/sec
nanoid 7,800,308 ops/sec
customAlphabet 9,697,350 ops/sec
nanoid for browser 576,759 ops/sec
secure-random-string 529,253 ops/sec
uid-safe.sync 526,459 ops/sec
Non-secure:
uid 31,379,525 ops/sec
nanoid/non-secure 3,678,505 ops/sec
rndm 3,767,185 ops/sec
Среда сравнения: Framework 13 7840U, Fedora 39, Node.js 21.6.
См. также хорошую статью о теориях генераторов случайных чисел: Secure random values (in Node.js)
Непредсказуемость. Вместо предсказуемого Math.random(), Nano ID
использует модуль crypto в Node.js и Web Crypto API в браузере.
Эти модули дают доступ к аппаратному генератору случайных чисел.
Равномерность. Например, существует популярная ошибка random % alphabet,
которую часто допускают при разработке генератора ID.
Распределение вероятности для каждого символа может не быть одинаковым.
Из-за неравномерности использования пространства алфавита, на перебор ID
потребуется меньше времени, чем ожидается.
Nano ID использует более совершенный алгоритм,
а равномерность распределения символов покрыта тестами.
Документация: все хитрости Nano ID хорошо документированы — смотрите комментарии в исходниках.
Уязвимости: если вы нашли уязвимость в Nano ID, свяжитесь с командой безопасности Tidelift. Они проконтролируют исправление и проинформируют пользователей.
Nano ID 5 работает с ESM-проектами (import) в тестах или скриптах для Node.js.
npm install nanoid
На проектах с CommonJS вы можете использовать:
require() будет работать в последней версия Node.js 22.12 (из коробки)
или Node.js 20 (с флагом --experimental-require-module).
В более старых версиях Node.js можно использовать динамический импорт:
let nanoid
module.exports.createID = async () => {
if (!nanoid) ({ nanoid } = await import('nanoid'))
return nanoid() // => "V1StGXR8_Z5jdHi6B-myT"
}
Или можно просто взять Nano ID 3.x (мы его всё ещё поддерживаем):
npm install nanoid@3
JSR это замена npm с открытым управлением и активной разработкой (в отличие от npm).
npx jsr add @sitnik/nanoid
Вы можете использовать пакет с JSR в Node.js, Deno, Bun.
// Replace `nanoid` to `@sitnik/nanoid` in all imports
import { nanoid } from '@sitnik/nanoid'
Для Deno установите через deno add jsr:@sitnik/nanoid
или импортируйте jsr:@sitnik/nanoid.
Для быстрого прототипирования вы можете подключить Nano ID с CDN без установки. Не используйте этот способ на реальном сайте, так как он сильно бьёт по скорости загрузки сайта.
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
Nano ID разделён на два модуля: стандартный и небезопасный.
По умолчанию используются символы, безопасные для URL (A-Za-z0-9_-).
Длина ID по умолчанию — 21 символ
(чтобы вероятность коллизий была соизмеримой с UUID v4).
Безопасный и простой в использовании способ использования Nano ID.
Из-за особенностей работы генератора случайных чисел при использовании этого способа ЦПУ может иногда простаивать без работы.
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
Функция также принимает необязательный аргумент, задающий длину ID:
nanoid(10) //=> "IRFa-VaY2b"
При изменении размера, всегда проверяйте риски в нашем калькуляторе коллизий.
По умолчанию, Nano ID использует аппаратный генератор случайных чисел для получения непредсказуемых ID и минимизации риска возникновения коллизий (повторной генерации ранее выданных ID). Но если вам не требуется устойчивость к подбору ID, то вы можете перейти на небезопасный генератор — это полезно там, где нет доступа к API аппаратного генератора случайных чисел.
import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
Но учтите, что предсказуемость ID может быть использована для атаки на систему.
Функция customAlphabet позволяет создать свою функцию nanoid
с нужным вам алфавитом и длиной ID.
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid() //=> "4f90d13a42"
import { customAlphabet } from 'nanoid/non-secure'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid()
Не забудьте проверить риски коллизии вашего алфавита и длины
на нашем калькуляторе. nanoid-dictionary содержит много популярных
примеров альтернативных алфавитов.
Алфавит должен содержать ≤256 символов. Иначе мы не сможем гарантировать непредсказуемость ID.
Длину ID можно менять не только в customAlphabet(), но и при вызове
генератора, который она вернёт:
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"
Функция customRandom позволяет создать свою функцию nanoid со своими
генераторами случайных чисел, алфавитом и длинной ID.
Например, можно использовать генератор c seed для повторяемости тестов.
import { customRandom } from 'nanoid'
const rng = seedrandom(seed)
const nanoid = customRandom('abcdef', 10, size => {
return new Uint8Array(size).map(() => 256 * rng())
})
nanoid() //=> "fbaefaadeb"
Функция в третьем аргументе customRandom должна принимать длину массива
и возвращать нужный массив со случайными числами
Если вы хотите заменить только генератор случайных чисел, но оставить
URL-совместимый алфавит, то стандартный алфавит доступен
в экспорте urlAlphabet.
const { customRandom, urlAlphabet } = require('nanoid')
const nanoid = customRandom(urlAlphabet, 10, random)
Не используйте Nano ID для генерации свойства key в JSX. При каждом рендере
key будет разный, что плохо скажется на производительности.
function Todos({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={nanoid()}>
{' '}
/* НЕ ДЕЛАЙТЕ ТАК */
{todo.text}
</li>
))}
</ul>
)
}
Для связи <input> и <label> лучше использовать useId,
который был добавлен в React 18.
React Native не имеет встроенного аппаратного генератора случайных чисел. Полифил ниже работает в чистом React Native и в Expo начиная с версии 39.
react-native-get-random-values и установите его.import 'react-native-get-random-values'
import { nanoid } from 'nanoid'
В PouchDB и CouchDB, ID не могут начинаться с _. Добавьте к ID префикс,
так как иногда Nano ID может сгенерировать ID начинающийся с _.
Изменить стандартный ID можно через следующую опцию:
db.put({
_id: 'id' + nanoid(),
…
})
Можно сгенерировать уникальный ID прямо из терминала, вызвав npx nanoid.
Для этого в системе должна быть только Node.js. npx сама скачает Nano ID,
если его нет в системе.
$ npx nanoid
npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxn
Длину генерируемых ID можно передать в аргументе --size (или -s):
$ npx nanoid --size 10
L3til0JS4z
Изменить алфавит можно при помощи аргумента --alphabet (ли -a)
(в этом случае --size обязателен):
$ npx nanoid --alphabet abc --size 15
bccbcabaabaccab
Nano ID позволяет приводить сгенерированные строки к непрозрачным строкам в TypeScript. Например:
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }
// Используйте явный параметр типа:
mockUser(nanoid<UserId>())
interface User {
id: UserId
name: string
}
const user: User = {
// Автоматически приводится к типу UserId:
id: nanoid(),
name: 'Alice'
}
Nano ID был портирован на множество языков. Это полезно, чтобы сервер и клиент генерировали ID по одной схеме.
Для остальных сред можно использовать Nano ID для терминала.
nanoid-dictionary с популярными алфавитами для customAlphabet.nanoid-good гарантирует, что в случайном ID не будет матерных слов.