From 0ea8a5307746f701fd10f4c9c2cb88c41c242050 Mon Sep 17 00:00:00 2001 From: Yuxin Wu Date: Tue, 29 Mar 2022 20:07:40 -0700 Subject: [PATCH] Async rendering of tags within a post --- lib/hexo/post.js | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/hexo/post.js b/lib/hexo/post.js index 7f0db61bbe..35b0ce05bb 100644 --- a/lib/hexo/post.js +++ b/lib/hexo/post.js @@ -29,6 +29,21 @@ const isNonWhiteSpaceChar = char => char !== '\r' && char !== '\v' && char !== ' '; +function replaceAsync(string, searchValue, replacer) { + // An alternative to string.replace, but with an async replacer. + // Reference: https://github.com/dsblv/string-replace-async + var values = []; + String.prototype.replace.call(string, searchValue, function () { + values.push(replacer.apply(undefined, arguments)); + return ""; + }); + return Promise.all(values).then(function (resolvedValues) { + return String.prototype.replace.call(string, searchValue, function () { + return resolvedValues.shift(); + }); + }); +} + class PostRenderEscape { constructor() { this.stored = []; @@ -47,11 +62,6 @@ class PostRenderEscape { }; } - restoreAllSwigTags(str) { - const restored = str.replace(rSwigPlaceHolder, PostRenderEscape.restoreContent(this.stored)); - return restored; - } - restoreCodeBlocks(str) { return str.replace(rCodeBlockPlaceHolder, PostRenderEscape.restoreContent(this.stored)); } @@ -415,17 +425,17 @@ class Post { path: source, engine: data.engine, toString: true, - onRenderEnd(content) { - // Replace cache data with real contents - data.content = cacheObj.restoreAllSwigTags(content); - - // Return content after replace the placeholders - if (disableNunjucks) return data.content; + }, options); + }).then(content => { + // Use replaceAsync so that tags within a post can render concurrently + return replaceAsync(content, rSwigPlaceHolder, async(match, name) => { + // Replace swig placeholder produced by `escapeAllSwigTags` with real contents stored previously + let ret = PostRenderEscape.restoreContent(cacheObj.stored)(match, name); + if (disableNunjucks) return ret; // Render with Nunjucks - return tag.render(data.content, data); - } - }, options); + return await tag.render(ret, data); + }); }).then(content => { data.content = cacheObj.restoreCodeBlocks(content);