Библиотека Marked предоставляет гибкие возможности для преобразования Markdown в HTML, включая поддержку асинхронной обработки. Асинхронная обработка особенно актуальна при работе с пользовательскими рендерерами, загрузкой внешних ресурсов или при необходимости выполнять операции, которые возвращают промисы.
Marked поддерживает асинхронный режим через функцию
marked.parse с опцией async: true. В этом
режиме обработка Markdown может возвращать промис, что
позволяет использовать await или then для
получения результата:
import { marked } from 'marked';
const markdown = '# Заголовок\n\nНекоторый текст';
async function parseMarkdown() {
const html = await marked.parse(markdown, { async: true });
console.log(html);
}
parseMarkdown();
Важный момент: при использовании асинхронного режима все пользовательские методы рендеринга и лексеры должны поддерживать промисы, иначе асинхронная обработка будет некорректной.
Marked позволяет определить собственные рендереры через объект
renderer. Каждый метод рендерера может быть
асинхронным:
const renderer = {
async link(href, title, text) {
// Имитация асинхронной проверки URL
await new Promise(resolve => setTimeout(resolve, 100));
return `<a href="${href}" title="${title || ''}">${text}</a>`;
}
};
const markdown = '[Google](https://google.com)';
marked.parse(markdown, { renderer, async: true }).then(html => {
console.log(html);
});
Ключевой момент: если рендерер возвращает промис,
нужно обязательно включать опцию async: true, иначе
результат будет некорректным.
Процесс преобразования Markdown в HTML проходит через лексический анализ (токенизацию) и рендеринг токенов. В асинхронном режиме возможна обработка каждого токена с использованием промисов:
import { Lexer, Parser } from 'marked';
const markdown = '';
async function asyncParse(markdown) {
const lexer = new Lexer();
const tokens = lexer.lex(markdown);
const parser = new Parser({
async image(token) {
// Асинхронная загрузка изображения или проверка URL
await new Promise(resolve => setTimeout(resolve, 50));
return `<img src="${token.href}" alt="${token.text}">`;
}
});
const html = await parser.parse(tokens, { async: true });
console.log(html);
}
asyncParse(markdown);
Такой подход особенно полезен для встраивания данных из внешних источников, например, изображений, ссылок или динамического контента.
Marked позволяет создавать пользовательские токены и
обрабатывать их асинхронно. Для этого используется объект
tokenizer:
const tokenizer = {
async myCustomToken(src) {
const match = /^:::(.+?)\n([\s\S]+?)\n:::/m.exec(src);
if (match) {
await new Promise(resolve => setTimeout(resolve, 100));
return {
type: 'myCustomToken',
raw: match[0],
info: match[1],
text: match[2]
};
}
}
};
const renderer = {
async myCustomToken(token) {
return `<div class="custom">${token.text}</div>`;
}
};
const markdown = `:::notice
Это важное сообщение
:::`;
marked.parse(markdown, { tokenizer, renderer, async: true }).then(html => {
console.log(html);
});
Это демонстрирует, как можно расширять синтаксис Markdown и обрабатывать новые конструкции асинхронно.
async: true при
использовании асинхронных рендереров или токенизаторов.Promise.all при генерации нескольких
блоков, чтобы ускорить асинхронные операции.try/catch или обработку .catch на
промисах.Marked допускает создание собственных плагинов для асинхронной обработки Markdown. Плагин может модифицировать токены, внедрять данные из API и изменять рендеринг:
function asyncPlugin() {
return {
async tokenizer(src) {
const match = /^%%(.+?)%%/m.exec(src);
if (match) {
await new Promise(resolve => setTimeout(resolve, 50));
return { type: 'asyncToken', raw: match[0], content: match[1] };
}
},
async renderer(token) {
if (token.type === 'asyncToken') {
return `<span class="async">${token.content}</span>`;
}
}
};
}
const { tokenizer, renderer } = asyncPlugin();
marked.parse('%%Асинхронный контент%%', { tokenizer, renderer, async: true }).then(html => {
console.log(html);
});
Использование плагинов позволяет централизовать асинхронные преобразования и повторно применять их в разных проектах.
Асинхронная обработка в Marked расширяет возможности библиотеки и делает возможным интеграцию Markdown с динамическим контентом и внешними API, сохраняя при этом высокую производительность и гибкость.