API потоков Node.js
Нативная привязка pdf-oxide предоставляет читаемые потоки для результатов поиска, страниц и таблиц — это идиоматично для конвейеров Node.js и экономно по памяти при работе с большими документами.
Все потоки реализуют стандартный интерфейс Readable из Node.js в объектном режиме, поддерживают backpressure, интегрируются с pipe() и работают с асинхронной итерацией for await.
Потоки доступны в нативной привязке Node.js. В сборке WASM выполняйте итерацию синхронно.
SearchStream
Отдаёт по одному SearchResult по мере того, как нижележащий SearchManager находит совпадения.
const { PdfDocument, SearchManager, SearchStream } = require("pdf-oxide");
const doc = new PdfDocument("large.pdf");
const manager = new SearchManager(doc);
const stream = new SearchStream(manager, "invoice");
stream.on("data", (r) => {
console.log(`page ${r.pageIndex + 1}: ${r.text}`);
});
stream.on("end", () => {
console.log("search complete");
doc.close();
});
stream.on("error", (err) => {
console.error(err);
doc.close();
});
Поиск с учётом регистра
const stream = new SearchStream(manager, "Invoice", { caseSensitive: true });
Асинхронная итерация
for await (const result of stream) {
if (result.pageIndex > 50) break;
console.log(result.text);
}
Совместимость с pipe()
const { Writable } = require("stream");
const sink = new Writable({
objectMode: true,
write(result, _enc, cb) {
console.log(`${result.pageIndex}:${result.text}`);
cb();
},
});
stream.pipe(sink);
PageIteratorStream
Отдаёт извлечённый текст по одной странице за раз. Удобно для построчного вывода или когда вы подаёте данные в LLM через очередь с ограничением скорости.
const { PageIteratorStream } = require("pdf-oxide");
const stream = new PageIteratorStream(doc, { format: "markdown" });
for await (const { pageIndex, content } of stream) {
await indexPage(pageIndex, content);
}
format принимает значения "text" (по умолчанию), "markdown", "html", "plain".
TableStream
Отдаёт по одной таблице по мере их обнаружения.
const { TableStream } = require("pdf-oxide");
const stream = new TableStream(doc);
stream.on("data", (table) => {
console.log(`${table.rows.length}x${table.rows[0].length} on page ${table.pageIndex}`);
});
Backpressure
Все потоки реализуют стандартный механизм backpressure из Node.js. Если ваш потребитель работает медленно, поток приостанавливает извлечение, пока .read() не возобновит чтение:
stream.on("data", async (result) => {
stream.pause();
await slowIndex(result);
stream.resume();
});
Либо используйте for await, который выполняет приостановку автоматически.
Обработка ошибок
Ошибки во время извлечения отдаются как стандартные события error:
stream.on("error", (err) => {
if (err.code === "PDF_INVALID_PAGE") {
console.warn("skipping invalid page", err.pageIndex);
} else {
throw err;
}
});
Эффективность по памяти
Потоки удерживают в работе только один результат за раз. На PDF из 10 000 страниц с 50 000 совпадений SearchStream использует постоянный объём памяти — весь набор результатов никогда не материализуется целиком.
Очистка ресурсов
Закрытие родительского PdfDocument завершает все привязанные потоки. Кроме того, потоки освобождают ссылку на свой менеджер при событиях end / error.
const doc = new PdfDocument("big.pdf");
const stream = new SearchStream(new SearchManager(doc), "TODO");
stream.on("end", () => doc.close());
stream.on("error", () => doc.close());
В Node.js 22+ ключевое слово using освобождает документ при выходе из области видимости:
{
using doc = new PdfDocument("big.pdf");
const stream = new SearchStream(new SearchManager(doc), "TODO");
for await (const r of stream) console.log(r);
} // doc.close() called automatically
Связанные страницы
- Начало работы с Node.js — установка, быстрый старт
- Справочник API Node.js
- Поиск — варианты поиска без потоков