Cache ranges for Highlight.js syntax markers
The cache is saving 5-10% time for syntax layer. Since the syntax layer process whole files (not only diff chunks) there is a lot of duplicity between original and modified file (left and right diff). Calculation of ranges is an quite expensive operation, so any saving for skipping calculation is improving the time of javascript execution. Change-Id: I0976f25238c452a1240e96e4631e0aa9686dfa67
This commit is contained in:
@@ -259,12 +259,14 @@
|
||||
lastNotify: {left: 1, right: 1},
|
||||
};
|
||||
|
||||
const rangesCache = new Map();
|
||||
|
||||
this._processPromise = util.makeCancelable(this._loadHLJS()
|
||||
.then(() => {
|
||||
return new Promise(resolve => {
|
||||
const nextStep = () => {
|
||||
this._processHandle = null;
|
||||
this._processNextLine(state);
|
||||
this._processNextLine(state, rangesCache);
|
||||
|
||||
// Move to the next line in the section.
|
||||
state.lineIndex++;
|
||||
@@ -321,12 +323,21 @@
|
||||
* Highlight.js emits and emit a list of text ranges and classes for the
|
||||
* markers.
|
||||
* @param {string} str The string of HTML.
|
||||
* @param {Map<string, !Array<!Object>>} rangesCache A map for caching
|
||||
* ranges for each string. A cache is read and written by this method.
|
||||
* Since diff is mostly comparing same file on two sides, there is good rate
|
||||
* of duplication at least for parts that are on left and right parts.
|
||||
* @return {!Array<!Object>} The list of ranges.
|
||||
*/
|
||||
_rangesFromString(str) {
|
||||
_rangesFromString(str, rangesCache) {
|
||||
const cached = rangesCache.get(str);
|
||||
if (cached) return cached;
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = str;
|
||||
return this._rangesFromElement(div, 0);
|
||||
const ranges = this._rangesFromElement(div, 0);
|
||||
rangesCache.set(str, ranges);
|
||||
return ranges;
|
||||
},
|
||||
|
||||
_rangesFromElement(elem, offset) {
|
||||
@@ -357,7 +368,7 @@
|
||||
* lines).
|
||||
* @param {!Object} state The processing state for the layer.
|
||||
*/
|
||||
_processNextLine(state) {
|
||||
_processNextLine(state, rangesCache) {
|
||||
let baseLine;
|
||||
let revisionLine;
|
||||
|
||||
@@ -386,7 +397,8 @@
|
||||
baseLine = this._workaround(this._baseLanguage, baseLine);
|
||||
result = this._hljs.highlight(this._baseLanguage, baseLine, true,
|
||||
state.baseContext);
|
||||
this.push('_baseRanges', this._rangesFromString(result.value));
|
||||
this.push('_baseRanges',
|
||||
this._rangesFromString(result.value, rangesCache));
|
||||
state.baseContext = result.top;
|
||||
}
|
||||
|
||||
@@ -395,7 +407,8 @@
|
||||
revisionLine = this._workaround(this._revisionLanguage, revisionLine);
|
||||
result = this._hljs.highlight(this._revisionLanguage, revisionLine,
|
||||
true, state.revisionContext);
|
||||
this.push('_revisionRanges', this._rangesFromString(result.value));
|
||||
this.push('_revisionRanges',
|
||||
this._rangesFromString(result.value, rangesCache));
|
||||
state.revisionContext = result.top;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -388,10 +388,20 @@ limitations under the License.
|
||||
'<span class="non-whtelisted-class">',
|
||||
'<span class="gr-diff gr-syntax gr-syntax-keyword">public</span>',
|
||||
'</span>'].join('');
|
||||
const result = element._rangesFromString(str);
|
||||
const result = element._rangesFromString(str, new Map());
|
||||
assert.notEqual(result.length, 0);
|
||||
});
|
||||
|
||||
test('_rangesFromString cache same syntax markers', () => {
|
||||
sandbox.spy(element, '_rangesFromElement');
|
||||
const str =
|
||||
'<span class="gr-diff gr-syntax gr-syntax-keyword">public</span>';
|
||||
const cacheMap = new Map();
|
||||
element._rangesFromString(str, cacheMap);
|
||||
element._rangesFromString(str, cacheMap);
|
||||
assert.isTrue(element._rangesFromElement.calledOnce);
|
||||
});
|
||||
|
||||
test('_isSectionDone', () => {
|
||||
let state = {sectionIndex: 0, lineIndex: 0};
|
||||
assert.isFalse(element._isSectionDone(state));
|
||||
|
||||
Reference in New Issue
Block a user