From 68f7b94e9612e8d9134b27089ca5429fd1f6d3c5 Mon Sep 17 00:00:00 2001 From: Yuxin Wu Date: Sun, 18 Sep 2022 16:12:32 -0700 Subject: [PATCH] Faster rendering by less split --- lib/hexo/post.js | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/lib/hexo/post.js b/lib/hexo/post.js index 817173041b..fe8e610b0d 100644 --- a/lib/hexo/post.js +++ b/lib/hexo/post.js @@ -418,15 +418,37 @@ class Post { toString: true }, options); }).then(content => { + // This function restores swig tags in `content` and render them. + if (disableNunjucks) { + // If rendering is disabled, do nothing. + return cacheObj.restoreAllSwigTags(content); + } + // We'd like to render tags concurrently, so we split `content` + // by top-level HTML nodes that have swig tags into `split_content` array + // (nodes that don't have swig tags don't need to be split). + // Then we render items in `split_content` asynchronously. const doc = parse5.parseFragment(content); - // Indepedently render the tags in each top-level node - // asynchronously. This can significantly speed up rendering of slow tags - const results = doc.childNodes.map(async node => { - // Replace cache data with real contents - const content = cacheObj.restoreAllSwigTags(parse5.serializeOuter(node)); - // If disabled, return content after replacing the placeholders - if (disableNunjucks) return content; - // Render with Nunjucks + const split_content = []; + let current = []; // Current list of nodes to be added to split_content. + doc.childNodes.forEach(node => { + const html = parse5.serializeOuter(node); + const restored = cacheObj.restoreAllSwigTags(html); + current.push(restored); + if (html !== restored) { + // Once we encouner a node that has swig tags, merge + // all content we've seen so far and add to `split_content`. + // We don't simply add every node to `split_content`, because + // most nodes don't have swig tags and calling `tag.render` for + // all of them has significant overhead. + split_content.push(current.join('')); + current = []; + } + }); + if (current.length) { + split_content.push(current.join('')); + } + // Render the tags in each top-level node asynchronously. + const results = split_content.map(async content => { return await tag.render(content, data); }); return Promise.all(results).then(x => x.join(''));