TGViewer
Настоящий JavaScript Настоящий JavaScript @true_js · 5.89K subscribers
Post #3607 316
⁣Buffer в браузере: портирование Node.js-кода на Web Streams API и неочевидные грабли с TextEncoder/TextDecoder в production

Перетащить обработку бинарных данных из Node.js в браузер — берешь Buffer, оборачиваешь в Uint8Array и production падает. Проблема в том, что Buffer — глобал из Node.js, его нет в браузере, а полифилы тащат лишние килобайты. Современный путь — Web Streams API и TextEncoder/TextDecoder, но есть грабли, которые ломают production.

Грабли 1. slice не уважает UTF-8

В Node.js Buffer.from('Привет!').slice(0, 5) дает 5 байт и строку 'Прив'. В браузере new TextEncoder().encode('Привет!').slice(0, 5) режет посреди многобайтового символа — получаешь битый байт. В production это вылезает при обрезании логов с кириллицей или эмодзи. Решение: не используй slice на Uint8Array вслепую, применяй subarray и TextDecoder с stream: true для восстановления границ.

Грабли 2. Потоковое декодирование без stream: true

Web Streams отдают данные чанками. Если декодировать каждый чанк как отдельную строку, последний может быть урезан — многобайтовый символ разобьется на два чанка. Типичная ошибка:
// Ломается на границе чанков
for await (const chunk of reader) {
const str = new TextDecoder().decode(chunk);
}

Нужно так:
const decoder = new TextDecoder('utf-8', { stream: true });
for await (const chunk of reader) {
const str = decoder.decode(chunk, { stream: true });
}
const final = decoder.decode(); // завершающий вызов

Пропустишь stream: true — получишь битые данные на границах чанков, например, при парсинге CSV с кириллицей в production.

Грабли 3. Утечка памяти из-за создания инстансов

Создание new TextEncoder() внутри цикла или хендлера запросов вызывает GC-шторм. Вынеси в константы модуля один раз. Тоже самое с TextDecoder — кэшируй для всех чанков потока.

Практические советы при портировании

- Buffer.concat заменяй на ручное объединение через new Uint8Array(totalLength) и set.
- fs.createReadStream заменяй на fetch + response.body (ReadableStream).
- Для энкодинга/декодинга используй только TextEncoder/TextDecoder с stream: true на чанках.
- Никогда не доверяй прямому slice по Uint8Array, если внутри UTF-8 — это ломает строки с акцентами, кириллицей и эмодзи в production.

Вывод: Грабли не в том, что Buffer нет в браузере, а в том, что TextEncoder.encode ведет себя иначе — учитывай многобайтовые символы, кэшируй инстансы и всегда декодируй с stream: true.
More from @true_js
  1. Oct 3, 2026Post #3963
  2. Oct 2, 2026😅 Айтишник отправил в одну компанию три одинаковых резюме и только одно дошло до финала О…
  3. Oct 2, 2026Post #3961
  4. Oct 2, 2026🤣 Правильно расставленные приоритеты в моей жизни би лайк: 💥 xCode Journal
  5. Oct 1, 2026🤯 Люди взбунтовались против «пыточной для ИИ» На GitHub заметили открытый проект AI Tortu…
  6. Oct 1, 2026День в Заонежье начинается ещё в дороге. Мы встретим вас в аэропорту или на вокзале. Дальш…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →