Как эффективно заполнять массивы и не блокировать - PullRequest
0 голосов
/ 05 января 2020

Сценарий выглядит следующим образом ...

Шаблон компонента

<template>
  <div>
   <loader v-show="loading"></loader> // loading animation
   <div v-show="!loading">
     <div v-for="group in groups">
       {{group.name}}
       <div v-for="item in group.list">
         {{item.name}}
       </div>
     </div>
   </div>
  </div>
</template>

Данные компонента

data: function () {
    return {
        list: [],
        groups: [],
        loading: true
    }
}

1. получить одномерный массив из API

axios.get(API_URL).then(
    (response) => {
        this.list = response.data.payload;
    }
);

Структура массива следующая ...

[
  {
    "name": "bob",
    "group": "A"
  },
  {
    "name": "sally",
    "group": "A"
  },
  {
    "name": "john",
    "group": "B"
  },
  {
    "name": "jane",
    "group": "B"
  },
]

2. преобразовать массив в 2 измерения, используя свойство группы каждого элемента

текущее решение ( блокировка! , неэффективно? )

// loading animation stops at this point
this.list.forEach((item, index) => {
    let hasGroupChanged = false;
    if (index === 0) {
        hasGroupChanged = true;
    } else {
        let currentGroupName = item.group;
        let previousGroupName = this.list[index - 1].group;
        hasGroupChanged = previousGroupName !== currentGroupName;
    }
    if (hasGroupChanged) {
        const group = {
            group: item.group,
            list: []
        };
        this.groups.push(group);
    }
    const groupIndex = this.groups.length - 1;
    this.groups[groupIndex].list.push(item);
});

this.loading = false;

как сохранить анимацию загрузки до заполнения групп?

Ответы [ 3 ]

1 голос
/ 05 января 2020

Ваша анимация «загрузки» «заморожена», потому что JavaScript является однопоточным, и когда ваш код преобразования выполняется (при условии, что данных гораздо больше, чем показано в примере, поэтому он выполняется в течение значительного периода времени), рендеринг в браузере заблокирован.

Либо вы можете оптимизировать код преобразования, чтобы ускорить его, либо взглянуть на этот SO-ответ , чтобы узнать подробности и узнать, как сделать так, чтобы длительные операции не выполнялись. блокировать рендеринг браузера ....

0 голосов
/ 05 января 2020

Я не могу говорить об эффективности вашего кода, но простой способ поддерживать индикатор загрузки до тех пор, пока не завершится асинхронная операция c, - это остановить его в finally -блоке:

const btn = document.getElementById('btn');
const mockLoadIndicator = document.getElementById('loading');
const data = [
  {
    "name": "bob",
    "group": "A"
  }, {
    "name": "sally",
    "group": "A"
  }, {
    "name": "john",
    "group": "B"
  }, {
    "name": "jane",
    "group": "B"
  }
];
const mockAPI = () => {
  mockLoadIndicator.style.display = 'block';
  return new Promise((resolve) => {
    setTimeout(() => resolve(data), 1000);
  });
};

btn.onclick = () => mockAPI()
.then(console.log)
.finally(() => {
  mockLoadIndicator.style.display = 'none';
});
#loading {
  position: relative;
  display: none;
  height: 10px;
  width: 10px;
  border-radius: 50%;
  background: grey;
  animation-duration: 300ms;
  animation-name: load;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

@keyframes load {
  from {
    left: 10px;
  }
  to {
    left: 40px;
  }
}
<button id="btn">Get Data</button>
<div id="loading"></div>
0 голосов
/ 05 января 2020

Полагаю, проблема в том, что вы устанавливаете загрузку в false до того, как ax ios завершит получение ваших данных (потому что это единственная асинхронная c операция в коде).

.forEach, возможно, можно немного оптимизировать, но я сомневаюсь, что это виновник.

Попробуйте переместить весь свой код в .then вместо axios.get().

...