From 1dc5ee3ee1a8c3ca183ef849df2c67c843bcaaa2 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sun, 14 Feb 2021 14:59:50 +0300 Subject: [PATCH] Make optimize synchronous (#1322) Ref https://github.com/svg/svgo/issues/1015 Looks like `sax` is synchronous and we do not need to listen "end" event. This allows to avoid all callbacks and make `optimize` method synchronous. --- examples/test.js | 24 +++++++------- lib/svgo.js | 75 ++++++++++++++++-------------------------- lib/svgo/coa.js | 31 +++++++++-------- lib/svgo/svg2js.js | 23 +++---------- package.json | 5 +++ test/plugins/_index.js | 9 +++-- test/svg2js/_index.js | 14 +++----- test/svgo/_index.js | 7 ++-- 8 files changed, 75 insertions(+), 113 deletions(-) diff --git a/examples/test.js b/examples/test.js index e4f4fa43..bf5801ce 100644 --- a/examples/test.js +++ b/examples/test.js @@ -82,20 +82,18 @@ FS.readFile(filepath, 'utf8', function(err, data) { throw err; } - svgo.optimize(data, {path: filepath}).then(function(result) { + const result = svgo.optimize(data, {path: filepath}); - console.log(result); + console.log(result); - // { - // // optimized SVG data string - // data: 'test' - // // additional info such as width/height - // info: { - // width: '10', - // height: '20' - // } - // } - - }); + // { + // // optimized SVG data string + // data: 'test' + // // additional info such as width/height + // info: { + // width: '10', + // height: '20' + // } + // } }); diff --git a/lib/svgo.js b/lib/svgo.js index 7d6c2fa3..24a88678 100755 --- a/lib/svgo.js +++ b/lib/svgo.js @@ -21,56 +21,37 @@ var SVGO = function(config) { this.config = CONFIG(config); }; -SVGO.prototype.optimize = function(svgstr, info) { - info = info || {}; - return new Promise((resolve, reject) => { - if (this.config.error) { - reject(this.config.error); - return; +SVGO.prototype.optimize = function(svgstr, info = {}) { + const config = this.config; + if (config.error) { + throw Error(config.error); + } + const maxPassCount = config.multipass ? 10 : 1; + let prevResultSize = Number.POSITIVE_INFINITY; + let svgjs = null; + for (let i = 0; i < maxPassCount; i += 1) { + svgjs = SVG2JS(svgstr); + if (svgjs.error == null) { + svgjs = PLUGINS(svgjs, info, config.plugins); } - - var config = this.config, - maxPassCount = config.multipass ? 10 : 1, - counter = 0, - prevResultSize = Number.POSITIVE_INFINITY, - optimizeOnceCallback = (svgjs) => { - if (svgjs.error) { - reject(svgjs.error); - return; - } - - info.multipassCount = counter; - if (++counter < maxPassCount && svgjs.data.length < prevResultSize) { - prevResultSize = svgjs.data.length; - this._optimizeOnce(svgjs.data, info, optimizeOnceCallback); - } else { - if (config.datauri) { - svgjs.data = encodeSVGDatauri(svgjs.data, config.datauri); - } - if (info && info.path) { - svgjs.path = info.path; - } - resolve(svgjs); - } - }; - - this._optimizeOnce(svgstr, info, optimizeOnceCallback); - }); -}; - -SVGO.prototype._optimizeOnce = function(svgstr, info, callback) { - var config = this.config; - - SVG2JS(svgstr, function(svgjs) { + svgjs = JS2SVG(svgjs, config.js2svg); if (svgjs.error) { - callback(svgjs); - return; + throw Error(svgjs.error); } - - svgjs = PLUGINS(svgjs, info, config.plugins); - - callback(JS2SVG(svgjs, config.js2svg)); - }); + info.multipassCount = i; + if (svgjs.data.length < prevResultSize) { + prevResultSize = svgjs.data.length + } else { + if (config.datauri) { + svgjs.data = encodeSVGDatauri(svgjs.data, config.datauri); + } + if (info && info.path) { + svgjs.path = info.path; + } + return svgjs; + } + } + return svgjs; }; /** diff --git a/lib/svgo/coa.js b/lib/svgo/coa.js index d743cc94..ea6c3393 100644 --- a/lib/svgo/coa.js +++ b/lib/svgo/coa.js @@ -382,24 +382,23 @@ function processSVGData(config, info, data, output, input) { var startTime = Date.now(), prevFileSize = Buffer.byteLength(data, 'utf8'); - return svgo.optimize(data, info).then(function(result) { - if (config.datauri) { - result.data = encodeSVGDatauri(result.data, config.datauri); - } - var resultFileSize = Buffer.byteLength(result.data, 'utf8'), - processingTime = Date.now() - startTime; + const result = svgo.optimize(data, info); + if (config.datauri) { + result.data = encodeSVGDatauri(result.data, config.datauri); + } + var resultFileSize = Buffer.byteLength(result.data, 'utf8'), + processingTime = Date.now() - startTime; - return writeOutput(input, output, result.data).then(function() { - if (!config.quiet && output != '-') { - if (input) { - console.log(`\n${PATH.basename(input)}:`); - } - printTimeInfo(processingTime); - printProfitInfo(prevFileSize, resultFileSize); + return writeOutput(input, output, result.data).then(function() { + if (!config.quiet && output != '-') { + if (input) { + console.log(`\n${PATH.basename(input)}:`); } - }, - error => Promise.reject(new Error(error.code === 'ENOTDIR' ? `Error: output '${output}' is not a directory.` : error))); - }); + printTimeInfo(processingTime); + printProfitInfo(prevFileSize, resultFileSize); + } + }, + error => Promise.reject(new Error(error.code === 'ENOTDIR' ? `Error: output '${output}' is not a directory.` : error))); } /** diff --git a/lib/svgo/svg2js.js b/lib/svgo/svg2js.js index 6bba13e5..85a38b5f 100644 --- a/lib/svgo/svg2js.js +++ b/lib/svgo/svg2js.js @@ -19,16 +19,14 @@ var config = { * Convert SVG (XML) string to SVG-as-JS object. * * @param {String} data input data - * @param {Function} callback */ -module.exports = function(data, callback) { +module.exports = function(data) { var sax = SAX.parser(config.strict, config), root = new JSAPI({ elem: '#document', content: [] }), current = root, stack = [root], - textContext = null, - parsingError = false; + textContext = null; function pushToContent(content) { @@ -163,23 +161,12 @@ module.exports = function(data, callback) { }; - sax.onend = function() { - - if (!this.error) { - callback(root); - } else { - callback({ error: this.error.message }); - } - - }; - try { - sax.write(data); + sax.write(data).close(); + return root; } catch (e) { - callback({ error: e.message }); - parsingError = true; + return { error: e.message }; } - if (!parsingError) sax.close(); function trim(elem) { if (!elem.content) return elem; diff --git a/package.json b/package.json index 1a142e55..df288bfd 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,11 @@ "name": "Lev Solntsev", "email": "lev.sun@ya.ru", "url": "http://github.com/GreLI" + }, + { + "name": "Bogdan Chadkin", + "email": "trysound@yandex.ru", + "url": "http://github.com/TrySound" } ], "repository": { diff --git a/test/plugins/_index.js b/test/plugins/_index.js index 0209dd5a..c66c83e1 100644 --- a/test/plugins/_index.js +++ b/test/plugins/_index.js @@ -44,10 +44,9 @@ describe('plugins tests', function() { js2svg : { pretty: true } }); - return svgo.optimize(orig, {path: file}).then(function(result) { - //FIXME: results.data has a '\n' at the end while it should not - normalize(result.data).should.be.equal(should); - }); + const result = svgo.optimize(orig, {path: file}); + //FIXME: results.data has a '\n' at the end while it should not + normalize(result.data).should.be.equal(should); }); }); @@ -69,4 +68,4 @@ function readFile(file) { resolve(data); }); }); -} \ No newline at end of file +} diff --git a/test/svg2js/_index.js b/test/svg2js/_index.js index 7528d344..b93a83db 100644 --- a/test/svg2js/_index.js +++ b/test/svg2js/_index.js @@ -30,10 +30,8 @@ describe('svg2js', function() { throw err; } - SVG2JS(data, function(result) { - root = result; - done(); - }); + root = SVG2JS(data) + done(); }); }); @@ -423,9 +421,7 @@ describe('svg2js', function() { } try { - SVG2JS(data, function(result) { - root = result; - }); + root = SVG2JS(data) } catch (e) { error = e; } @@ -473,9 +469,7 @@ describe('svg2js', function() { FS.readFile(filepath, 'utf8', function(err, data) { if (err) throw err; - SVG2JS(data, function(result) { - root = result; - }); + root = SVG2JS(data); done(); }); }); diff --git a/test/svgo/_index.js b/test/svgo/_index.js index 327c5de7..c8552a36 100644 --- a/test/svgo/_index.js +++ b/test/svgo/_index.js @@ -30,10 +30,9 @@ describe('indentation', function() { js2svg : { pretty: true, indent: 2 } }); - svgo.optimize(orig, {path: filepath}).then(function(result) { - normalize(result.data).should.be.equal(should); - done(); - }); + const result = svgo.optimize(orig, {path: filepath}); + normalize(result.data).should.be.equal(should); + done(); });