Как оптимизировать / ускорить автоматический поиск c в приложении Vue JS? - PullRequest
1 голос
/ 08 января 2020

Мы реализовали функцию поиска по массиву из 1200 записей, с 6 фильтрами и ключевым словом поиска. Когда пользователь выбирает какой-либо из фильтров или вводит ключевое слово, поиск 'automati c' выполняется для фильтрации отображаемых результатов. Проблема заключается в том, что отфильтрованный массив перерисовывается медленнее, чем ожидалось, что приводит к зависанию приложения на долю секунды во время визуализации контента. Мой вопрос заключается в том, как оптимизировать следующий код, чтобы улучшить взаимодействие с пользователем, т. Е. При вводе поискового ключевого слова или выборе фильтров результаты должны отображаться быстро или таким образом, чтобы это не мешало пользователю?

Структура, которой мы располагаем, является родительским компонентом, который содержит 2 дочерних элемента: один - это Search бар, включающий фильтры в виде раскрывающихся списков, а другой - SearchResultsList, который отображает 4 Bootstrap - * 1024. * b-card с в строке до тех пор, пока список не будет исчерпан.

В родительском элементе мы отрисовываем двух дочерних элементов следующим образом:

<b-row
  class="pt-sm-4 p-sm-0 p-2 bg-white"
  no-gutters
>
  <b-col
    sm="12"
    class="px-sm-3 mb-4"
  >
    <!-- People Search Bar -->
    <practice-people-search
      :people="filteredPeopleByKeyword"
      @togglePracticePeopleFiltersEvent="onTogglePracticePeopleFiltersEvent"/>

    <!-- Practice People Search Results List -->
    <practice-people-search-results-list
      :people="filteredPeopleByKeyword"
      :show-practice-people-filters="showPracticePeopleFilters"/>
  </b-col>
</b-row>

У нас также есть крюк created и некоторые computed properties, которые соответственно выполняют внутренний вызов для получения данных и фильтрации входящего массива. Сначала мы фильтруем большой массив из 1200 записей, используя фильтр по умолчанию и / или любые другие выбранные фильтры, а затем фильтруем вновь созданный массив, когда пользователь вводит ключевое слово, например:

computed: {
    ...mapState('practice', [
      'practicePeopleKeyword',
      'practicePeopleCurrentValue',
      'practicePeopleOfficesValue',
      'practicePeopleGroupsValue',
      'practicePeopleOMGsValue',
      'practicePeopleStatusValue',
      'practicePeoplePositionValue']),
    filteredPeopleByFilters () {
      let filteredPeopleByFiltersArray = []
      for (let i = 0; i < this.people.length; i++) {
        let person = this.people[i]

        let currentResult = (this.practicePeopleCurrentValue.length === 0 || this.practicePeopleCurrentValue.filter((v) => {
          let cr = true
          switch (v.Value) {
            case 0:
              cr = (person.practiceCurrent === 1) && (person.officeCurrent === 1) && (person.groupCurrent === 1)
              break
            case 1:
              cr = (person.practiceCurrent === 0) && (person.started === 1)
              break
            case 2:
              cr = (person.practiceCurrent === 1) && (person.officeCurrent === 0)
              break
            case 3:
              cr = (person.practiceCurrent === 1) && (person.groupCurrent === 0)
              break
            case 4:
              cr = (person.started === 0)
              break
          }
          return cr
        }).length !== 0)
        let officeResult = (this.practicePeopleOfficesValue.length === 0 || this.practicePeopleOfficesValue.filter((v) => { return v.Value === person.mo_ref }).length !== 0)
        let groupResult = (this.practicePeopleGroupsValue.length === 0 || this.practicePeopleGroupsValue.filter((v) => { return v.Value === person.gp_ref }).length !== 0)
        let omgResult = (this.practicePeopleOMGsValue.length === 0 || this.practicePeopleOMGsValue.filter((v) => { return v.Value === person.omg_ref }).length !== 0)
        let statusResult = (this.practicePeopleStatusValue.length === 0 || this.practicePeopleStatusValue.filter((v) => {
          return (v.Value === person.mk_ref) || (v.Value === person.md_type)
        }).length !== 0)
        let positionResult = (this.practicePeoplePositionValue.length === 0 || this.practicePeoplePositionValue.filter((v) => {
          return v.Value === person.ms_ref || ((v.Value === -2) && (person.isPE === 1))
        }).length !== 0)

        if (currentResult && officeResult && groupResult && omgResult & statusResult && positionResult) {
          filteredPeopleByFiltersArray.push(person)
        }
      }
      return filteredPeopleByFiltersArray
    },
    filteredPeopleByKeyword () {
      let filteredPeopleByKeywordArray = []
      for (let i = 0; i < this.filteredPeopleByFilters.length; i++) {
        let person = this.filteredPeopleByFilters[i]

        let searchKeywordResult = (this.practicePeopleKeyword === '' || person.psname.indexOf(this.practicePeopleKeyword) > -1)

        if (searchKeywordResult) {
          filteredPeopleByKeywordArray.push(person)
        }
      }
      return filteredPeopleByKeywordArray
    }
  }

Код в practice-people-search компонент имеет вычисленные свойства, чтобы понять, какие фильтры были выбраны, и сохранить их в Vuex, в то время как practice-people-search-results-list компонент просто визуализирует поступающую пропу :people="filteredPeopleByKeyword"

Я надеюсь, что вышеизложенное имеет смысл и будет благодарен, если кто-нибудь идеи о том, как можно ускорить поиск, чтобы избежать или хотя бы минимизировать глюки? Приветствия

1 Ответ

2 голосов
/ 08 января 2020

Фильтрация 1200 элементов не должна быть заметна. В показанном коде или в другом месте приложения должна быть некоторая неэффективность.

Убедитесь, что filteredPeopleByFilters() не вызывается при каждом изменении practicePeopleKeyword, а только при смене фильтров. Вы можете сделать это с быстрым временным console.log. То же самое для filteredPeopleByKeyword() - убедитесь, что оно вызывается только один раз для каждого обновления.

Также в if (currentResult && officeResult && groupResult && omgResult & statusResult && positionResult) вы не получаете выгоды от короткого замыкания. Измените его на что-то вроде

    let currentResult = ...
    if (!currentResult) continue;
    let officeResult = ...
    if (!officeResult) continue;
    let groupResult = ...
    if (!groupResult) continue;
    ... etc ...

Пишите меньше кода. Использование встроенных функций часто может ускорить JS код.

Например, попробуйте заменить

filteredPeopleByKeyword () {
  let filteredPeopleByKeywordArray = []
  for (let i = 0; i < this.filteredPeopleByFilters.length; i++) {
    let person = this.filteredPeopleByFilters[i]

    let searchKeywordResult = (this.practicePeopleKeyword === '' || person.psname.indexOf(this.practicePeopleKeyword) > -1)

    if (searchKeywordResult) {
      filteredPeopleByKeywordArray.push(person)
    }
  }
  return filteredPeopleByKeywordArray
}

на

filteredPeopleByKeyword () {
  return this.filteredPeopleByFilters.filter(
    person => person.psname.indexOf(this.practicePeopleKeyword) > -1
  )
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...