Как заполнить массивы эффективно и без блокировки
Сценарий выглядит следующим образом...
Шаблон компонента
<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. извлечение 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 измерения с помощью свойства group каждого элемента
текущее решение (блокировка!- неэффективно?)
// 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;
как сохранить анимацию загрузки до тех пор, пока группы не будут заполнены?

Ответы - Как заполнить массивы эффективно и без блокировки / How to populate arrays efficiently and non blocking

05.01.2020 04:30:23
Я предполагаю, что проблема заключается в том, что вы устанавливаете loading в false до того, как axios закончит получать ваши данные (потому что это единственная асинхронная операция в коде).
Тот самый .forEach
, вероятно, можно было бы немного оптимизировать, но я сомневаюсь, что это виновник.
Попробуйте переместить весь ваш код в поле .then
приковал от axios.get()
вместо этого.

05.01.2020 04:56:25
Я действительно не могу говорить об эффективности вашего кода, но простой способ сохранить индикатор загрузки до завершения асинхронной операции-это остановить его в 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>

05.01.2020 05:02:01
Ваша анимация "загрузки" "заморожена", потому что JavaScript является однопоточным, и когда ваш код преобразования выполняется (предполагая, что существует гораздо больше данных, чем показано в Примере, поэтому он выполняется в течение значительного времени), визуализация браузера блокируется.
Либо вы можете оптимизировать код преобразования, чтобы сделать его быстрее, либо вы можете взглянуть на это, поэтому ответьте за детали и решения, как сделать длительные операции, чтобы не блокировать рендеринг браузера....