В Web Crypto API большинство операций являются асинхронными и часто выполняются вне основного JavaScript-потока, однако это не означает их «бесплатность» с точки зрения производительности. При профилировании важно учитывать не только время криптографического алгоритма, но и накладные расходы на подготовку данных, копирование буферов и переходы между слоями движка браузера и нативной криптографической подсистемы.
Ключевая метрика, которая используется на практике, — общее время
выполнения операции от момента вызова crypto.subtle.* до
получения результата промиса. Однако этого недостаточно: внутри этого
интервала могут скрываться совершенно разные по природе задержки.
Типичная операция Web Crypto API включает несколько фаз:
Наиболее частые узкие места возникают не в самом криптоалгоритме, а на границах между этими этапами.
Одним из наиболее недооценённых факторов производительности является
работа с ArrayBuffer, TypedArray и текстовыми
кодировками.
Каждый вызов TextEncoder.encode() создаёт новый
буфер:
const enc = new TextEncoder();
const data = enc.encode("some large payload");
При массовых операциях (например, потоковое шифрование сообщений) это становится значительным источником аллокаций и давления на сборщик мусора.
Web Crypto API почти всегда работает с копиями данных. Даже если
передаётся ArrayBuffer, движок может:
Это особенно заметно при больших объёмах данных (десятки мегабайт), где стоимость копирования начинает сопоставляться со стоимостью самого алгоритма.
Хотя crypto.subtle работает асинхронно, это не означает
минимальных накладных расходов. Каждый вызов:
await crypto.subtle.encrypt(...)
включает:
При массовых операциях (например, тысячи подписей или проверок) именно управление промисами может стать ограничивающим фактором.
Операции вроде:
crypto.subtle.generateKey(...)
или:
crypto.subtle.importKey(...)
являются значительно более дорогими, чем шифрование или хэширование. Причина — работа с:
При частом создании ключей система начинает упираться в криптографический RNG и системные вызовы.
Асимметричные алгоритмы обладают высокой вычислительной стоимостью:
При профилировании важно учитывать, что даже аппаратное ускорение не устраняет полностью их стоимость, а лишь снижает её.
Симметричные алгоритмы вроде AES-GCM обычно значительно быстрее, но их производительность зависит от:
Небольшие частые вызовы часто оказываются медленнее, чем одна большая операция, из-за накладных расходов на вызов API.
При интенсивной работе с Web Crypto API формируется большое количество временных объектов:
Это приводит к:
Особенно заметно в сценариях потокового шифрования, где данные разбиваются на мелкие части.
Для измерения реальной производительности используется
performance.now():
const t0 = performance.now();
await crypto.subtle.encrypt(alg, key, data);
const t1 = performance.now();
Однако более точные измерения требуют:
performance.mark()performance.measure()Пример группового измерения:
performance.mark("start-encrypt");
for (let i = 0; i < 1000; i++) {
await crypto.subtle.encrypt(alg, key, chunks[i]);
}
performance.mark("end-encrypt");
performance.measure("encrypt-total", "start-encrypt", "end-encrypt");
В браузерной среде важно учитывать, что:
Для анализа используются:
При реализации потокового шифрования часто возникают проблемы:
encrypt/decryptОптимальная стратегия — увеличение размера блока до диапазона 64KB–1MB в зависимости от сценария.
Часто криптографические операции сопровождаются преобразованием:
Base64 особенно затратен:
При профилировании часто выясняется, что именно кодирование занимает
больше времени, чем crypto.subtle.encrypt.
Web Crypto API частично освобождает от необходимости ручного параллелизма, но при высоких нагрузках выгодно использовать:
Однако при этом возникает новая проблема: стоимость передачи данных между потоками через structured cloning.
На практике наиболее частые причины деградации производительности:
subtleПроизводительность Web Crypto API зависит от:
Одинаковый код может демонстрировать различие в производительности в разы.
При анализе узких мест обычно выделяются три слоя:
crypto.subtle)Точное определение узкого места возможно только при раздельном измерении каждого слоя с использованием комбинации DevTools и ручных замеров.