Skip to content

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() викликається автоматично

Пов’язані сторінки