Работа с асинхронным API

Библиотека Marked позволяет преобразовывать Markdown в HTML с высокой скоростью и гибкостью. Для работы с асинхронным API важно корректно настроить парсер и понимать, какие функции поддерживают асинхронную обработку.

Установка производится через npm:

npm install marked

Импорт в модуле ES6:

import { marked } from 'marked';

Для работы с асинхронными функциями необходимо использовать marked.parse с передачей функции обратного вызова или промиса, так как синхронный метод marked.parse блокирует выполнение и не подходит для асинхронных источников данных.

Асинхронная обработка

Асинхронное API Marked позволяет использовать пользовательские функции рендеринга и загрузки контента. Основной метод:

await marked.parse(markdownString, options);

Асинхронный рендеринг ссылок и изображений

Возможность асинхронной обработки важна при динамическом формировании ссылок, изображений или вставке данных из внешних API. Для этого используется кастомный Renderer:

const renderer = {
  async image(href, title, text) {
    const optimizedSrc = await fetchOptimizedImage(href);
    return `<img src="${optimizedSrc}" alt="${text}" title="${title || ''}">`;
  },
  async link(href, title, text) {
    const validatedHref = await validateLink(href);
    return `<a href="${validatedHref}" title="${title || ''}">${text}</a>`;
  }
};

const html = await marked.parse(markdownString, { renderer });

Ключевой момент — методы рендерера могут быть асинхронными, и marked.parse корректно ожидает их выполнение.

Настройка токенизатора

Tokenizers позволяют добавлять или изменять правила парсинга Markdown. Для асинхронного использования можно комбинировать токенизатор с внешними запросами:

const tokenizer = {
  async link(src) {
    const match = src.match(/\[([^\]]+)\]\(([^)]+)\)/);
    if (!match) return;
    const [ , text, href ] = match;
    const resolvedHref = await resolveDynamicLink(href);
    return {
      type: 'link',
      raw: match[0],
      text,
      href: resolvedHref
    };
  }
};

const html = await marked.parse(markdownString, { tokenizer });

Токенизатор может выполнять любые асинхронные операции, включая сетевые запросы, при этом сохраняется корректная последовательность парсинга.

Асинхронные хуки

Marked поддерживает хуки на различных этапах рендеринга. Для асинхронного API ключевые хуки:

  • walkTokens: асинхронный обход токенов перед рендерингом.
  • async walkTokens: возможность трансформировать или фильтровать токены с ожиданием внешних данных.

Пример использования walkTokens для асинхронной обработки:

const options = {
  async walkTokens(token) {
    if (token.type === 'image') {
      token.href = await optimizeImage(token.href);
    }
    if (token.type === 'link') {
      token.href = await validateLink(token.href);
    }
  }
};

const html = await marked.parse(markdownString, options);

Важно понимать, что асинхронные хуки позволяют выполнять модификацию токенов до их финального преобразования в HTML без блокировки основного потока.

Потоковая обработка Markdown

Для больших документов или потоковых данных можно использовать marked.lexer и асинхронные функции обработки:

const tokens = marked.lexer(markdownStream);
for (const token of tokens) {
  if (token.type === 'link') {
    token.href = await resolveLink(token.href);
  }
}
const html = marked.parser(tokens);

Такой подход минимизирует задержки при работе с внешними API и позволяет обрабатывать большие объемы данных по частям.

Практическое использование

Асинхронное API Marked особенно полезно при:

  • Подгрузке данных для ссылок и изображений из внешних сервисов.
  • Генерации контента на лету (например, документации с динамическими вставками).
  • Фильтрации или модификации токенов на основе сетевых запросов или базы данных.

Все операции могут быть встроены в единый асинхронный поток, где await marked.parse() обеспечивает корректный порядок выполнения, а кастомные рендереры и токенизаторы позволяют гибко управлять финальным HTML-контентом.

Настройки производительности

Для асинхронного использования рекомендуется:

  • Использовать walkTokens вместо полного рендерера, если модификации минимальны.
  • Разбивать большие Markdown-документы на части и обрабатывать их параллельно через Promise.all.
  • Кэшировать результаты сетевых запросов для ускорения повторного рендеринга.

Эти подходы позволяют сохранять высокую скорость парсинга и одновременно использовать асинхронные источники данных без блокировки.