Remark и Rehype — это две комплементарные библиотеки для работы с текстовыми документами в формате Markdown и HTML. Remark выполняет разбор Markdown в промежуточное дерево MDAST (Markdown Abstract Syntax Tree), а Rehype работает с деревом HAST (HTML Abstract Syntax Tree). Важно понимать, что обе библиотеки построены с концепцией плагинов, которые позволяют трансформировать деревья на различных этапах обработки.
Параллельная обработка документов подразумевает одновременное выполнение нескольких плагинов или обработку множества документов без блокировки основного потока выполнения. Для этого используется асинхронная модель Node.js и возможность комбинирования плагинов с промисами.
Большинство плагинов Remark и Rehype поддерживают асинхронное выполнение. Это означает, что плагин может выполнять операции с файловой системой, сетевые запросы или другие ресурсоёмкие задачи без блокировки основного потока. Пример структуры асинхронного плагина:
async function asyncPlugin() {
return async (tree, file) => {
// Асинхронная трансформация
await someAsyncOperation(tree);
};
}
Асинхронные плагины можно комбинировать в цепочку с помощью
.use(), при этом Remark и Rehype корректно обрабатывают
промисы и выполняют их в порядке подключения.
Для массовой обработки документов используется
Promise.all или специализированные библиотеки для
управления параллельными потоками, например p-limit:
import fs fr om 'fs/promises';
import {remark} fr om 'remark';
import remarkHtml fr om 'remark-html';
import pLimit from 'p-lim it';
const files = ['doc1.md', 'doc2.md', 'doc3.md'];
const lim it = pLimit(5); // Максимум 5 одновременных обработок
const tasks = files.map(file =>
lim it(async () => {
const content = await fs.readFile(file, 'utf-8');
const result = await remark().use(remarkHtml).process(content);
await fs.writeFile(file.replace('.md', '.html'), result.toString());
})
);
await Promise.all(tasks);
В данном примере создается пул одновременных задач, что позволяет контролировать нагрузку на систему при обработке большого числа файлов.
Часто требуется сначала преобразовать Markdown в HTML с помощью Remark, а затем выполнить дополнительные трансформации через Rehype, например:
Пример последовательной обработки:
import {remark} from 'remark';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
const result = await remark()
.use(remarkRehype)
.use(rehypeAutolinkHeadings)
.use(rehypeStringify)
.process(markdownContent);
Асинхронные плагины Rehype также могут быть объединены с асинхронными Remark-плагинами для параллельной обработки большого числа документов.
worker_threads или
child_process. Это позволяет полностью использовать
многоядерные процессоры.fs.readFileSync, блокируют поток и снижают пропускную
способность.Remark и Rehype позволяют создавать собственные плагины для параллельной обработки документов. Например, плагин для загрузки и вставки изображений из сети может выполняться асинхронно:
import fetch from 'node-fetch';
import {visit} from 'unist-util-visit';
export default function imageFetcher() {
return async (tree) => {
const promises = [];
visit(tree, 'image', (node) => {
promises.push(
fetch(node.url)
.then(res => res.buffer())
.then(buffer => {
node.data = {buffer};
})
);
});
await Promise.all(promises);
};
}
Такой подход позволяет одновременно обрабатывать все изображения в документе, не блокируя основной поток обработки.
Promise.all или пул
потоков.Эта схема обеспечивает высокую производительность и масштабируемость, позволяя обрабатывать большие объёмы документации, блогов, учебных материалов и других текстовых ресурсов.