Awesomplete строит свою работу вокруг событийного цикла, который
запускается при изменении значения поля ввода и последующей обработке
массива данных. В основе лежит связка из нескольких этапов: получение
ввода, фильтрация списка, построение выпадающего меню, навигация по
элементам и выбор значения. Трассировка выполнения в этом контексте
означает наблюдение за тем, как данные проходят через каждый из этих
этапов, и фиксацию состояния внутреннего объекта
Awesomplete в ключевых точках.
Каждое действие пользователя инициирует цепочку вызовов, которую можно перехватить и проанализировать через переопределение методов, подписку на события и внедрение промежуточных логов.
Основной поток выполнения начинается с обработчика события
input на связанном текстовом поле. Внутри библиотеки это
приводит к вызову метода:
Awesomplete.evaluate()Этот метод является центральной точкой, через которую проходит каждое изменение строки.
Трассировка на этом этапе обычно начинается с фиксации исходного значения:
const originalEvaluate = Awesomplete.prototype.evaluate;
Awesomplete.prototype.evaluate = function() {
console.log("evaluate triggered");
console.log("input value:", this.input.value);
console.log("minChars:", this.minChars);
return originalEvaluate.apply(this, arguments);
};
Здесь фиксируется момент входа в цикл обработки и начальное состояние входных данных.
После входа в evaluate() происходит подготовка данных и
вызов фильтра:
Awesomplete.FILTER_CONTAINSНа этом этапе происходит сравнение строки ввода с элементами списка. Для трассировки важно фиксировать:
this._listПример перехвата:
const originalFilter = Awesomplete.FILTER_CONTAINS;
Awesomplete.FILTER_CONTAINS = function(text, input) {
const result = originalFilter(text, input);
console.log("filter check:", { text, input, result });
return result;
};
Если используется кастомный фильтр, трассировка переносится внутрь
функции, переданной в конфигурации filter.
После фильтрации формируется массив this._filtered.
Далее вызывается метод:
Awesomplete.open()Он отвечает за создание DOM-структуры списка.
Ключевые точки трассировки:
const originalOpen = Awesomplete.prototype.open;
Awesomplete.prototype.open = function() {
console.log("dropdown opening");
console.log("filtered items:", this._filtered.length);
return originalOpen.apply(this, arguments);
};
На этом этапе важно отслеживать соответствие между данными и DOM, особенно при динамическом изменении списка.
После открытия списка управление переходит к навигации через клавиши. Основные методы:
next()previous()Они изменяют индекс выделенного элемента this.index.
Трассировка включает:
const originalNext = Awesomplete.prototype.next;
Awesomplete.prototype.next = function() {
console.log("before next index:", this.index);
const result = originalNext.apply(this, arguments);
console.log("after next index:", this.index);
return result;
};
Подобный подход позволяет выявить ошибки в логике навигации, особенно при кастомных списках или асинхронной подгрузке данных.
Ключевой этап выполнения — выбор значения через:
Awesomplete.select()Или через replace() внутри обработки события клика.
На этом этапе происходит:
Трассировка:
const originalSelect = Awesomplete.prototype.select;
Awesomplete.prototype.select = function(item, original) {
console.log("sel ect triggered:", item);
console.log("original value:", original);
return originalSelect.apply(this, arguments);
};
Здесь фиксируется соответствие между отображаемым значением и фактически подставляемым.
Awesomplete использует события DOM для уведомления о ключевых состояниях:
awesomplete-openawesomplete-closeawesomplete-selectawesomplete-selectcompleteТрассировка через события даёт более стабильный механизм наблюдения, чем monkey patching:
input.addEventListener("awesomplete-open", () => {
console.log("event: open");
});
input.addEventListener("awesomplete-select", (e) => {
console.log("event: select", e.text);
});
События позволяют фиксировать момент, когда внутреннее состояние уже синхронизировано с DOM.
Для глубокой трассировки важны внутренние поля объекта:
this.inputthis.ulthis.indexthis._filteredthis._openИзменения этих значений можно логировать через проксирование объекта:
const instance = new Awesomplete(input, { list: ["apple", "banana", "cherry"] });
const proxy = new Proxy(instance, {
set(target, prop, value) {
console.log(`state change: ${prop} =`, value);
target[prop] = value;
return true;
}
});
Такой подход полезен при анализе сложных багов, связанных с рассинхронизацией состояния.
При динамическом обновлении list выполнение проходит
через повторную фильтрацию и перерисовку. Важно отслеживать:
this.listevaluate()ulПример наблюдения:
Object.defineProperty(instance, "list", {
set(value) {
console.log("list updated:", value);
this._list = value;
this.evaluate();
},
get() {
return this._list;
}
});
Для комплексного анализа удобно использовать группировку логов:
console.group("Awesomplete trace");
console.log("input:", this.input.value);
console.log("filtered:", this._filtered);
console.log("index:", this.index);
console.groupEnd();
Это позволяет визуально восстанавливать цепочку выполнения при множественных событиях ввода.
Одной из ключевых задач трассировки является проверка соответствия:
this._filtered ↔︎ DOM элементы lithis.index ↔︎ выделенный элементНесоответствие этих структур часто указывает на:
Для диагностики используется сверка:
console.log(
Array.fr om(instance.ul.children).length,
instance._filtered.length
);
Методы open() и evaluate() могут вызываться
многократно при быстром вводе. Трассировка позволяет выявить избыточные
вызовы:
Типичный приём — измерение времени выполнения:
const t0 = performance.now();
instance.evaluate();
const t1 = performance.now();
console.log("evaluate time:", t1 - t0);
Полная трассировка включает фиксацию:
input.addEventListener("keydown", (e) => {
console.log("keydown:", e.key);
});
input.addEventListener("blur", () => {
console.log("blur event");
});
Это позволяет восстановить точную последовательность действий, приведших к конкретному состоянию компонента.