From 223f2c6c821a9a1debe20fa0890f3b0d56e34e27 Mon Sep 17 00:00:00 2001 From: dailyrandomphoto <51783821+dailyrandomphoto@users.noreply.github.com> Date: Thu, 10 Oct 2019 18:15:09 +0800 Subject: [PATCH] perf(cache): improve cache and reduce Memory Usages (#3756) * test(cache): verify whether the cache works properly * fix(fragment_cache): reset the cache on generateBefore event so we can enable cache on watch mode. * fix(cache): disable save cache for rendered contents when generate files. Added at (https://github.com/hexojs/hexo/commit/e8e45ed0f379f975147a214fbf52b2c28a6c806a#diff-b9bb6fa7bb069bab9948daba90c6c3b2). Should enable save cache for rendered contents when run server mode. --- lib/hexo/index.js | 18 +++++++-- lib/plugins/helper/fragment_cache.js | 5 ++- test/scripts/helpers/fragment_cache.js | 11 +++++- test/scripts/hexo/hexo.js | 55 ++++++++++++++++++++++---- 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/lib/hexo/index.js b/lib/hexo/index.js index 065b7619d3..eff22f0c4c 100644 --- a/lib/hexo/index.js +++ b/lib/hexo/index.js @@ -51,6 +51,7 @@ function Hexo(base = process.cwd(), args = {}) { silent: Boolean(args.silent), env: process.env.NODE_ENV || 'development', version: pkg.version, + cmd: args._ ? args._[0] : '', init: false }; @@ -253,11 +254,16 @@ Hexo.prototype.load = function(callback) { this.source.process(), this.theme.process() ]); - }).then(() => this._generate({cache: true})).asCallback(callback); + }).then(() => this._generate({cache: false})).asCallback(callback); }; Hexo.prototype.watch = function(callback) { - this._watchBox = debounce(() => this._generate({cache: false}), 100); + let useCache = false; + if (this.env.cmd.startsWith('s')) { + // enable cache when run hexo server + useCache = true; + } + this._watchBox = debounce(() => this._generate({cache: useCache}), 100); return loadDatabase(this).then(() => { this.log.info('Start processing'); @@ -270,7 +276,7 @@ Hexo.prototype.watch = function(callback) { this.source.on('processAfter', this._watchBox); this.theme.on('processAfter', this._watchBox); - return this._generate({cache: false}); + return this._generate({cache: useCache}); }).asCallback(callback); }; @@ -345,6 +351,8 @@ const createLoadThemeRoute = function(generatorResult, locals, ctx) { const layout = unique(castArray(generatorResult.layout)); const layoutLength = layout.length; + // allways use cache in fragment_cache + locals.cache = true; return () => { if (useCache && routeCache.has(generatorResult)) return routeCache.get(generatorResult); @@ -355,7 +363,9 @@ const createLoadThemeRoute = function(generatorResult, locals, ctx) { if (view) { log.debug(`Rendering HTML ${name}: ${chalk.magenta(path)}`); return view.render(locals).tap(result => { - routeCache.set(generatorResult, result); + if (useCache) { + routeCache.set(generatorResult, result); + } }).tapCatch(err => { log.error({ err }, `Render HTML failed: ${chalk.magenta(path)}`); }); diff --git a/lib/plugins/helper/fragment_cache.js b/lib/plugins/helper/fragment_cache.js index 95c1a9a5fe..6510b8de7b 100644 --- a/lib/plugins/helper/fragment_cache.js +++ b/lib/plugins/helper/fragment_cache.js @@ -1,7 +1,10 @@ 'use strict'; module.exports = ctx => { - const cache = {}; + let cache = {}; + + // reset cache for watch mode + ctx.on('generateBefore', () => { cache = {}; }); return function fragmentCache(id, fn) { if (this.cache && cache[id] != null) return cache[id]; diff --git a/test/scripts/helpers/fragment_cache.js b/test/scripts/helpers/fragment_cache.js index 5a816cb0cf..92ff914fe6 100644 --- a/test/scripts/helpers/fragment_cache.js +++ b/test/scripts/helpers/fragment_cache.js @@ -1,7 +1,9 @@ 'use strict'; describe('fragment_cache', () => { - const fragment_cache = require('../../../lib/plugins/helper/fragment_cache')(); + const Hexo = require('../../../lib/hexo'); + const hexo = new Hexo(__dirname); + const fragment_cache = require('../../../lib/plugins/helper/fragment_cache')(hexo); fragment_cache.call({cache: true}, 'foo', () => 123); @@ -12,4 +14,11 @@ describe('fragment_cache', () => { it('cache disabled', () => { fragment_cache.call({cache: false}, 'foo', () => 456).should.eql(456); }); + + it('should reset cache on generateBefore', () => { + fragment_cache.call({cache: true}, 'foo', () => 789).should.eql(456); + // reset cache + hexo.emit('generateBefore'); + fragment_cache.call({cache: true}, 'foo', () => 789).should.eql(789); + }); }); diff --git a/test/scripts/hexo/hexo.js b/test/scripts/hexo/hexo.js index c0f0c1758b..52e98d769c 100644 --- a/test/scripts/hexo/hexo.js +++ b/test/scripts/hexo/hexo.js @@ -62,6 +62,7 @@ describe('Hexo', () => { silent: false, env: process.env.NODE_ENV || 'development', version, + cmd: '', init: false }); hexo.config_path.should.eql(pathFn.join(__dirname, '_config.yml')); @@ -452,17 +453,41 @@ describe('Hexo', () => { it('_generate() - reset cache for new route', () => { let count = 0; - hexo.theme.setView('test.swig', '{{ page.count }}'); + hexo.theme.setView('test.swig', '{{ page.count() }}'); hexo.extend.generator.register('test', () => ({ path: 'test', layout: 'test', - data: {count: count++} + data: {count: () => count++} })); // First generation - return hexo._generate({cache: true}).then(() => checkStream(route.get('test'), '0')).then(() => // Second generation - hexo._generate({cache: true})).then(() => checkStream(route.get('test'), '1')); + return hexo._generate({cache: true}) + .then(() => checkStream(route.get('test'), '0')) + .then(() => checkStream(route.get('test'), '0')) // should return cached result + .then(() => hexo._generate({cache: true})) // Second generation + .then(() => checkStream(route.get('test'), '1')) + .then(() => checkStream(route.get('test'), '1')); // should return cached result + }); + + it('_generate() - cache disabled and use new route', () => { + let count = 0; + + hexo.theme.setView('test.swig', '{{ page.count() }}'); + + hexo.extend.generator.register('test', () => ({ + path: 'test', + layout: 'test', + data: {count: () => count++} + })); + + // First generation + return hexo._generate({cache: false}) + .then(() => checkStream(route.get('test'), '0')) + .then(() => checkStream(route.get('test'), '1')) + .then(() => hexo._generate({cache: false})) // Second generation + .then(() => checkStream(route.get('test'), '2')) + .then(() => checkStream(route.get('test'), '3')); }); it('_generate() - cache disabled & update template', () => { @@ -473,10 +498,24 @@ describe('Hexo', () => { layout: 'test' })); - return hexo._generate({cache: false}).then(() => checkStream(route.get('test'), '0')).then(() => { - hexo.theme.setView('test.swig', '1'); - return checkStream(route.get('test'), '1'); - }); + return hexo._generate({cache: false}) + .then(() => checkStream(route.get('test'), '0')) + .then(() => hexo.theme.setView('test.swig', '1')) + .then(() => checkStream(route.get('test'), '1')); + }); + + it('_generate() - cache enabled & update template', () => { + hexo.theme.setView('test.swig', '0'); + + hexo.extend.generator.register('test', () => ({ + path: 'test', + layout: 'test' + })); + + return hexo._generate({cache: true}) + .then(() => checkStream(route.get('test'), '0')) + .then(() => hexo.theme.setView('test.swig', '1')) + .then(() => checkStream(route.get('test'), '0')); // should return cached result }); it('execFilter()', () => {