Почему мой JavaScript-поиск НАМНОГО медленнее, если предыдущий поиск дал много результатов?
У меня действительно странный эффект в веб-приложении, которое я написал. Количество текущих результатов поиска оказывает огромное влияние на скорость следующего поиска, хотя поиск никоим образом не использует список результатов.
Я не уверен, сколько кода я должен опубликовать здесь, чтобы продемонстрировать, что приложение делает, но все приложение онлайн на http://connective-lex.info/. (Чтобы увидеть эффект, выберите все лексиконы, затем измените параметры поиска, например, отметьте один или ни одного.)
Это функция запроса. Первая строка отмечена !!!
, очищает предыдущий список результатов, что приводит к очень быстрым поискам. Если эта строка закомментирована, поиск начинается немного быстрее, но затем становится чрезвычайно медленным, если в предыдущем списке результатов много элементов.
Список результатов this.results
и не используется в поисковом коде. Он также не используется в классе ResultsFilter, который выполняет фактическую фильтрацию, которую я для краткости опущу, но с удовольствием выложу больше кода, если вам потребуется больше.
// File: c24-components.js
// Class: ResultsComponent
ExecuteQuery() {
setTimeout(() => this.SetResults([]), 0); // !!!
let tempResults = [];
let lexIds = Object.keys(gSelectorComponent.lex);
let totalSize = lexIds.map(lexId => gSelectorComponent.lex[lexId].entry.length).
reduce((acc, val) => acc + val, 0);
let resultsFilter = new ResultsFilter(totalSize);
let processAtOnce = 20;
this.activeSearches.forEach(timeoutId => clearTimeout(timeoutId));
this.activeSearches.length = 0;
/* Subfunction which emulates asynchronous processing in the (single-threaded)
JS environment by processing a slice of entries and then enqueuing the next
slice to be processed so that the browser has time to process user events
and render the GUI between slices. */
let processingFunction = (lexIdIndex, entryIndex) => {
if (lexIdIndex >= lexIds.length) {
this.activeSearches.push(setTimeout(() => this.SetResults(tempResults), 0));
return;
}
let entries = undefined;
try {
entries = gSelectorComponent.lex[lexIds[lexIdIndex]].entry;
} catch (e) {
// This happens when a lexicon is deselected while a search is running.
// Abort search.
return;
}
for (let i = 0; i < processAtOnce; ++i, ++entryIndex) {
if (entryIndex >= entries.length) {
this.activeSearches.push(setTimeout(processingFunction, 0, ++lexIdIndex, 0));
return;
}
if (resultsFilter.TestEntry(entries[entryIndex])) {
tempResults.push(entries[entryIndex]);
}
}
this.activeSearches.push(setTimeout(processingFunction, 0, lexIdIndex,
entryIndex));
};
this.activeSearches.push(setTimeout(processingFunction, 0, 0, 0));
}
Обновление: если я правильно интерпретирую инструменты производительности Chrome, это проблема перекомпоновки, вызванная обновлением индикатора выполнения. При каждом обновлении JS тратит много времени на операции рендеринга "Update Layer Tree", что, похоже, является единственным отличием, которое занимает больше времени, если отображается больше предыдущих результатов. Интересно, как я могу избавиться от этого эффекта, но все же показать прогресс.