Думаю, я понял это. Сначала я попытаюсь объяснить, что пошло не так, после чего я перейду к своему решению.
Проблема
В коде вопроса возникла проблема. Прежде чем было отправлено новое значение, я бы уже выполнил http-запрос в searchTrigger
, но не в searchTriggerEmpty
. Следовательно, searchTrigger
может быть испущено после того, как searchTriggerEmpty
даже жесткий searchTrigger
был начат первым.
Решение
Решение было исправить порядок эмиссии. Для этого событие должно быть отправлено до того, как будут сделаны какие-либо запросы. И когда запускается новое событие, предыдущее событие должно быть отменено (switchMap
-behavior).
Код объяснения
-
searchTrigger
генерирует события, когда кто-то печатает в
searchBox
.
- Добавлены некоторые трубы.
debounceTime( 500 )
и distinctUntilChanged()
предотвращают слишком частое срабатывание события.
- Канал
map
возвращает типы значений в searchBox.
- В
switchMap
есть условный оператор. Здесь выбирается лучший способ продолжить.
- Если строка длиннее 2 символов, она возвращает наблюдаемый массив символов CharacterIndexes (он получает их, выполняя некоторые http-запросы и обрабатывая их).
- Если строка короче, чем 2 символа, она будет напрямую возвращать пустой массив.
- Причина использования
switchMap
в том, что текущий ожидающий процесс будет отменен при отправке нового значения.
- Подписавшись на
searchTrigger
, мы теперь можем обрабатывать последние результаты поиска.
- Я также предоставил функцию, которую использовал для
process_searchString()
, чтобы вы лучше понимали, что она делает / возвращает.
Код
let searchBox = document.getElementById('search-box');
let searchTrigger = fromEvent(searchBox, 'input')
.pipe(
debounceTime( 500 ),
distinctUntilChanged(),
map((event: any) => event.target.value ),
switchMap( searchString => {
if( searchString.length > 2 ){
return this.process_searchString( searchString );
} else if ( searchString.length <= 2 ) {
return of( [] );
}
}),
);
searchTrigger.subscribe( ( characterIndexes: number[] ) => {
this.characterIndexes = characterIndexes;
this.characters = [];
if( characterIndexes.length > 0 ){
this.load_10characters();
}
});
Отказ от ответственности: На момент написания этого я только научился использовать rxjs. Так что, если вы видите что-то, что должно быть улучшено, напишите комментарий.
PS: Для тех, кто заинтересован, это видео объясняет карту SwitchMap лучше, чем я (и тоже интересно): https://www.youtube.com/watch?v=rUZ9CjcaCEw
Extra process_searchString()
:
private process_searchString( searchString: string ): Observable<number[]>{
return new BehaviorSubject( searchString )
.pipe(
concatMap( ( text: string ) => this.request_characterSearch( text ) ),
concatMap( ( response: any ) => {
if( response.character ){
return this.request_characterNames( response.character )
} else {
return of([]);
}
}),
map( (charactersInfo: any[]) => this.sort_alphabetically( charactersInfo ) ),
map( (charactersInfo: any[]) => charactersInfo.map( characterinfo => characterinfo.id ) ),
);
}