Skip to content

Commit ba6e0da

Browse files
committed
Merge PR jspreadsheet#1786: Performance improvement - replace eval() with globalThis check, arrays with Sets for formula chains
2 parents ba9a39a + 68801d7 commit ba6e0da

1 file changed

Lines changed: 23 additions & 26 deletions

File tree

src/utils/internal.js

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -175,62 +175,60 @@ export const executeFormula = function (expression, x, y) {
175175

176176
// Get tokens
177177
tokens = expression.match(/([A-Z]+[0-9]+)/g);
178+
tokens = new Set(tokens);
178179

179180
// Direct self-reference protection
180-
if (tokens && tokens.indexOf(parentId) > -1) {
181+
if (tokens && tokens.has(parentId)) {
181182
console.error('Self Reference detected');
182183
return '#ERROR';
183184
} else {
184185
// Expressions to be used in the parsing
185186
const formulaExpressions = {};
186187

187188
if (tokens) {
188-
for (let i = 0; i < tokens.length; i++) {
189+
for (const t of tokens) {
189190
// Keep chain
190-
if (!obj.formula[tokens[i]]) {
191-
obj.formula[tokens[i]] = [];
191+
if (!obj.formula[t]) {
192+
obj.formula[t] = new Set();
192193
}
193194
// Is already in the register
194-
if (obj.formula[tokens[i]].indexOf(parentId) < 0) {
195-
obj.formula[tokens[i]].push(parentId);
196-
}
195+
obj.formula[t].add(parentId);
197196

198197
// Do not calculate again
199-
if (eval('typeof(' + tokens[i] + ') == "undefined"')) {
198+
if (!(t in globalThis)) {
200199
// Coords
201-
const position = getIdFromColumnName(tokens[i], 1);
200+
const position = getIdFromColumnName(t, 1);
202201
// Get value
203202
let value;
204203

205-
if (typeof obj.options.data[position[1]] != 'undefined' && typeof obj.options.data[position[1]][position[0]] != 'undefined') {
204+
if (position[1] in obj.options.data && position[0] in obj.options.data[position[1]]) {
206205
value = obj.options.data[position[1]][position[0]];
207206
} else {
208207
value = '';
209208
}
210209
// Get column data
211210
if (('' + value).substr(0, 1) == '=') {
212-
if (typeof formulaResults[tokens[i]] !== 'undefined') {
213-
value = formulaResults[tokens[i]];
211+
if (t in formulaResults) {
212+
value = formulaResults[t];
214213
} else {
215214
value = execute(value, position[0], position[1]);
216-
formulaResults[tokens[i]] = value;
215+
formulaResults[t] = value;
217216
}
218217
}
219218
// Type!
220219
if (('' + value).trim() == '') {
221-
// Null
222-
formulaExpressions[tokens[i]] = null;
220+
delete formulaExpressions[t];
223221
} else {
224222
if (value == Number(value) && obj.parent.config.autoCasting != false) {
225223
// Number
226-
formulaExpressions[tokens[i]] = Number(value);
224+
formulaExpressions[t] = Number(value);
227225
} else {
228226
// Trying any formatted number
229227
const number = parseNumber.call(obj, value, position[0]);
230228
if (obj.parent.config.autoCasting != false && number) {
231-
formulaExpressions[tokens[i]] = number;
229+
formulaExpressions[t] = number;
232230
} else {
233-
formulaExpressions[tokens[i]] = '"' + value + '"';
231+
formulaExpressions[t] = '"' + value + '"';
234232
}
235233
}
236234
}
@@ -773,23 +771,23 @@ export const updateFormulaChain = function (x, y, records) {
773771
const obj = this;
774772

775773
const cellId = getColumnNameFromId([x, y]);
776-
if (obj.formula[cellId] && obj.formula[cellId].length > 0) {
774+
if (obj.formula[cellId] && obj.formula[cellId].size > 0) {
777775
if (chainLoopProtection[cellId]) {
778776
obj.records[y][x].element.innerHTML = '#ERROR';
779777
obj.formula[cellId] = '';
780778
} else {
781779
// Protection
782780
chainLoopProtection[cellId] = true;
783781

784-
for (let i = 0; i < obj.formula[cellId].length; i++) {
785-
const cell = getIdFromColumnName(obj.formula[cellId][i], true);
782+
for (const n of obj.formula[cellId]) {
783+
const cell = getIdFromColumnName(n, true);
786784
// Update cell
787785
const value = '' + obj.options.data[cell[1]][cell[0]];
788786
if (value.substr(0, 1) == '=') {
789787
records.push(updateCell.call(obj, cell[0], cell[1], value, true));
790788
} else {
791789
// No longer a formula, remove from the chain
792-
Object.keys(obj.formula)[i] = null;
790+
obj.formula[cellId].delete(n);
793791
}
794792
updateFormulaChain.call(obj, cell[0], cell[1], records);
795793
}
@@ -874,13 +872,12 @@ const updateFormulas = function (referencesToUpdate) {
874872
key = referencesToUpdate[key];
875873
}
876874
// Update values
877-
formula[key] = [];
878-
for (let i = 0; i < value.length; i++) {
879-
let letter = value[i];
875+
formula[key] = new Set();
876+
for (let letter of value) {
880877
if (referencesToUpdate[letter]) {
881878
letter = referencesToUpdate[letter];
882879
}
883-
formula[key].push(letter);
880+
formula[key].add(letter);
884881
}
885882
}
886883
obj.formula = formula;

0 commit comments

Comments
 (0)