Skip to content

Commit

Permalink
perf: refactor to make overall changes
Browse files Browse the repository at this point in the history
- Make some functions pure and move them to the top level
- Avoid some Promise overhead
- Utilize Array method on non-performance-intensive tasks
  • Loading branch information
SukkaW committed Sep 22, 2021
1 parent 0c979bf commit cf8d236
Show file tree
Hide file tree
Showing 5 changed files with 332 additions and 333 deletions.
17 changes: 6 additions & 11 deletions lib/hexo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ class Hexo extends EventEmitter {
]);
}).then(() => {
mergeCtxThemeConfig(this);
}).then(() => this._generate({cache: false})).asCallback(callback);
return this._generate({cache: false});
}).asCallback(callback);
}

watch(callback) {
Expand All @@ -346,7 +347,7 @@ class Hexo extends EventEmitter {
]);
}).then(() => {
mergeCtxThemeConfig(this);
}).then(() => {

this.source.on('processAfter', this._watchBox);
this.theme.on('processAfter', () => {
this._watchBox();
Expand Down Expand Up @@ -402,10 +403,8 @@ class Hexo extends EventEmitter {
return Promise.map(Object.keys(generators), key => {
const generator = generators[key];

return Reflect.apply(generator, this, [siteLocals]).then(data => {
log.debug('Generator: %s', magenta(key));
return data;
});
log.debug('Generator: %s', magenta(key));
return Reflect.apply(generator, this, [siteLocals]);
}).reduce((result, data) => {
return data ? result.concat(data) : result;
}, []);
Expand Down Expand Up @@ -434,11 +433,7 @@ class Hexo extends EventEmitter {
.thenReturn(path);
}).then(newRouteList => {
// Remove old routes
const removed = routeList.filter(item => !newRouteList.includes(item));

for (let i = 0, len = removed.length; i < len; i++) {
route.remove(removed[i]);
}
routeList.filter(item => !newRouteList.includes(item)).forEach(removed => route.remove(removed));
});
}

Expand Down
12 changes: 6 additions & 6 deletions lib/hexo/load_plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ function loadModules(ctx) {
function loadScripts(ctx) {
const baseDirLength = ctx.base_dir.length;

function displayPath(path) {
return magenta(path.substring(baseDirLength));
}

return Promise.filter([
ctx.theme_script_dir,
ctx.script_dir
Expand All @@ -71,9 +67,13 @@ function loadScripts(ctx) {
const path = join(scriptDir, name);

return ctx.loadPlugin(path).then(() => {
ctx.log.debug('Script loaded: %s', displayPath(path));
ctx.log.debug('Script loaded: %s', displayPath(path, baseDirLength));
}).catch(err => {
ctx.log.error({err}, 'Script load failed: %s', displayPath(path));
ctx.log.error({err}, 'Script load failed: %s', displayPath(path, baseDirLength));
});
}));
}

function displayPath(path, baseDirLength) {
return magenta(path.substring(baseDirLength));
}
46 changes: 25 additions & 21 deletions lib/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ const rHexoPostRenderEscape = /<hexoPostRenderCodeBlock>([\s\S]+?)<\/hexoPostRen
const rSwigPlaceHolder = /(?:<|&lt;)!--swig\uFFFC(\d+)--(?:>|&gt;)/g;
const rCodeBlockPlaceHolder = /(?:<|&lt;)!--code\uFFFC(\d+)--(?:>|&gt;)/g;

const _escapeContent = (cache, flag, str) => `<!--${flag}\uFFFC${cache.push(str) - 1}-->`;

const _restoreContent = cache => (_, index) => {
assert(cache[index]);
const value = cache[index];
cache[index] = null;
return value;
};

const STATE_PLAINTEXT = Symbol('plaintext');
const STATE_SWIG_VAR = Symbol('swig_var');
const STATE_SWIG_COMMENT = Symbol('swig_comment');
Expand All @@ -43,17 +34,30 @@ class PostRenderEscape {
this.stored = [];
}

static escapeContent(cache, flag, str) {
return `<!--${flag}\uFFFC${cache.push(str) - 1}-->`;
}

static restoreContent(cache) {
return (_, index) => {
assert(cache[index]);
const value = cache[index];
cache[index] = null;
return value;
};
}

restoreAllSwigTags(str) {
const restored = str.replace(rSwigPlaceHolder, _restoreContent(this.stored));
const restored = str.replace(rSwigPlaceHolder, PostRenderEscape.restoreContent(this.stored));
return restored;
}

restoreCodeBlocks(str) {
return str.replace(rCodeBlockPlaceHolder, _restoreContent(this.stored));
return str.replace(rCodeBlockPlaceHolder, PostRenderEscape.restoreContent(this.stored));
}

escapeCodeBlocks(str) {
return str.replace(rHexoPostRenderEscape, (_, content) => _escapeContent(this.stored, 'code', content));
return str.replace(rHexoPostRenderEscape, (_, content) => PostRenderEscape.escapeContent(this.stored, 'code', content));
}

/**
Expand Down Expand Up @@ -101,7 +105,7 @@ class PostRenderEscape {
} else {
swig_tag_name = '';
state = STATE_PLAINTEXT;
output += _escapeContent(this.stored, 'swig', `{%${buffer}%}`);
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${buffer}%}`);
}

buffer = '';
Expand All @@ -127,7 +131,7 @@ class PostRenderEscape {
if (char === '}' && next_char === '}') {
idx++;
state = STATE_PLAINTEXT;
output += _escapeContent(this.stored, 'swig', `{{${buffer}}}`);
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{{${buffer}}}`);
buffer = '';
} else {
buffer = buffer + char;
Expand Down Expand Up @@ -157,7 +161,7 @@ class PostRenderEscape {

if (swig_full_tag_end_buffer.includes(`end${swig_tag_name}`)) {
state = STATE_PLAINTEXT;
output += _escapeContent(this.stored, 'swig', `{%${swig_full_tag_start_buffer}%}${buffer}{%${swig_full_tag_end_buffer}%}`);
output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${swig_full_tag_start_buffer}%}${buffer}{%${swig_full_tag_end_buffer}%}`);
idx = _idx;
swig_full_tag_start_buffer = '';
swig_full_tag_end_buffer = '';
Expand Down Expand Up @@ -241,7 +245,8 @@ class Post {
createAssetFolder(path, config.post_asset_folder)
]).then(() => {
ctx.emit('new', result);
}).thenReturn(result);
return result;
});
}).asCallback(callback);
}

Expand Down Expand Up @@ -271,12 +276,11 @@ class Post {
// Parse front-matter
const obj = jsonMode ? JSON.parse(`{${frontMatter}}`) : load(frontMatter);

// Add data which are not in the front-matter
for (const key of Object.keys(data)) {
if (!preservedKeys.includes(key) && obj[key] == null) {
Object.keys(data)
.filter(key => !preservedKeys.includes(key) && obj[key] == null)
.forEach(key => {
obj[key] = data[key];
}
}
});

let content = '';
// Prepend the separator
Expand Down
188 changes: 94 additions & 94 deletions lib/plugins/processor/asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,124 +7,124 @@ const { extname, relative } = require('path');
const { Pattern } = require('hexo-util');

module.exports = ctx => {
function processPage(file) {
const Page = ctx.model('Page');
const { path } = file;
const doc = Page.findOne({source: path});
const { config } = ctx;
const { timezone: timezoneCfg } = config;
// Deprecated: use_date_for_updated will be removed in future
const updated_option = config.use_date_for_updated === true ? 'date' : config.updated_option;
return {
pattern: new Pattern(path => {
if (isExcludedFile(path, ctx.config)) return;

if (file.type === 'skip' && doc) {
return;
}
return {
renderable: ctx.render.isRenderable(path) && !isMatch(path, ctx.config.skip_render)
};
}),

if (file.type === 'delete') {
if (doc) {
return doc.remove();
process: function assetProcessor(file) {
if (file.params.renderable) {
return processPage(ctx, file);
}

return;
return processAsset(ctx, file);
}
};
};

return Promise.all([
file.stat(),
file.read()
]).spread((stats, content) => {
const data = yfm(content);
const output = ctx.render.getOutput(path);

data.source = path;
data.raw = content;
function processPage(ctx, file) {
const Page = ctx.model('Page');
const { path } = file;
const doc = Page.findOne({source: path});
const { config } = ctx;
const { timezone: timezoneCfg } = config;
// Deprecated: use_date_for_updated will be removed in future
const updated_option = config.use_date_for_updated === true ? 'date' : config.updated_option;

if (file.type === 'skip' && doc) {
return;
}

data.date = toDate(data.date);
if (file.type === 'delete') {
if (doc) {
return doc.remove();
}

if (data.date) {
if (timezoneCfg) data.date = timezone(data.date, timezoneCfg);
} else {
data.date = stats.ctime;
}
return;
}

data.updated = toDate(data.updated);
return Promise.all([
file.stat(),
file.read()
]).spread((stats, content) => {
const data = yfm(content);
const output = ctx.render.getOutput(path);

if (data.updated) {
if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg);
} else if (updated_option === 'date') {
data.updated = data.date;
} else if (updated_option === 'empty') {
data.updated = undefined;
} else {
data.updated = stats.mtime;
}
data.source = path;
data.raw = content;

if (data.permalink) {
data.path = data.permalink;
data.permalink = undefined;
data.date = toDate(data.date);

if (data.path.endsWith('/')) {
data.path += 'index';
}
if (data.date) {
if (timezoneCfg) data.date = timezone(data.date, timezoneCfg);
} else {
data.date = stats.ctime;
}

if (!extname(data.path)) {
data.path += `.${output}`;
}
} else {
data.path = `${path.substring(0, path.length - extname(path).length)}.${output}`;
}
data.updated = toDate(data.updated);

if (!data.layout && output !== 'html' && output !== 'htm') {
data.layout = false;
}
if (data.updated) {
if (timezoneCfg) data.updated = timezone(data.updated, timezoneCfg);
} else if (updated_option === 'date') {
data.updated = data.date;
} else if (updated_option === 'empty') {
data.updated = undefined;
} else {
data.updated = stats.mtime;
}

// FIXME: Data may be inserted when reading files. Load it again to prevent
// race condition. We have to solve this in warehouse.
const doc = Page.findOne({source: path});
if (data.permalink) {
data.path = data.permalink;
data.permalink = undefined;

if (doc) {
return doc.replace(data);
if (data.path.endsWith('/')) {
data.path += 'index';
}

return Page.insert(data);
});
}

function processAsset(file) {
const id = relative(ctx.base_dir, file.source).replace(/\\/g, '/');
const Asset = ctx.model('Asset');
const doc = Asset.findById(id);

if (file.type === 'delete') {
if (doc) {
return doc.remove();
if (!extname(data.path)) {
data.path += `.${output}`;
}
} else {
data.path = `${path.substring(0, path.length - extname(path).length)}.${output}`;
}

return;
if (!data.layout && output !== 'html' && output !== 'htm') {
data.layout = false;
}

return Asset.save({
_id: id,
path: file.path,
modified: file.type !== 'skip',
renderable: file.params.renderable
});
}
// FIXME: Data may be inserted when reading files. Load it again to prevent
// race condition. We have to solve this in warehouse.
const doc = Page.findOne({source: path});

return {
pattern: new Pattern(path => {
if (isExcludedFile(path, ctx.config)) return;
if (doc) {
return doc.replace(data);
}

return {
renderable: ctx.render.isRenderable(path) && !isMatch(path, ctx.config.skip_render)
};
}),
return Page.insert(data);
});
}

process: function assetProcessor(file) {
if (file.params.renderable) {
return processPage(file);
}
function processAsset(ctx, file) {
const id = relative(ctx.base_dir, file.source).replace(/\\/g, '/');
const Asset = ctx.model('Asset');
const doc = Asset.findById(id);

return processAsset(file);
if (file.type === 'delete') {
if (doc) {
return doc.remove();
}
};
};

return;
}

return Asset.save({
_id: id,
path: file.path,
modified: file.type !== 'skip',
renderable: file.params.renderable
});
}

0 comments on commit cf8d236

Please sign in to comment.