Ответ 1
Обновление: теперь мы также рассматриваем этот вопрос в эпизоде AskFirebase.
Загрузка многих элементов из Firebase не должна быть медленной, поскольку вы можете конвейерно запросить запросы. Но ваш код делает это невозможным, что действительно приведет к субоптимальной производительности.
В вашем коде вы запрашиваете элемент с сервера, дождитесь возвращения этого элемента и затем загрузите следующий. В упрощенной диаграмме последовательности, которая выглядит так:
Your app Firebase
Database
-- request item 1 -->
S L
e o
r a
v d
e i
<- return item 1 -- r n
g
-- request item 2 -->
S L
e o
r a
v d
e i
r n
<- return item 2 -- g
-- request item 3 -->
.
.
.
-- request item 30-->
S L
e o
r a
v d
e i
r n
g
<- return item 30 --
В этом сценарии вы ожидаете 30-кратного времени вашего перехвата времени + 30 раз больше времени, необходимого для загрузки данных с диска. Если (для простоты) мы говорим, что roundtrips занимают 1 секунду, а загрузка элемента с диска также занимает одну секунду, что меньше 30 * (1 + 1) = 60 секунд.
В приложениях Firebase вы получите гораздо лучшую производительность, если вы отправите все запросы (или, по крайней мере, разумное число из них) за один раз:
Your app Firebase
Database
-- request item 1 -->
-- request item 2 --> S L
-- request item 3 --> e o
. r a
. v d
. e i
-- request item 30--> r n
g
<- return item 1 --
<- return item 2 --
<- return item 3 --
.
.
.
<- return item 30 --
Если мы снова возьмем 1-секундный кругооборот и 1 секунду загрузки, вы ждете 30 * 1 + 1 = 31 секунд.
Итак: все запросы проходят через одно и то же соединение. Учитывая это, единственная разница между get(1)
, get(2)
, get(3)
и getAll([1,2,3])
- это некоторые издержки для фреймов.
Я установил jsbin, чтобы продемонстрировать поведение. Модель данных очень проста, но это показывает разницу.
function loadVideosSequential(videoIds) {
if (videoIds.length > 0) {
db.child('videos').child(videoIds[0]).once('value', snapshot => {
if (videoIds.length > 1) {
loadVideosSequential(videoIds.splice(1), callback)
}
});
}
}
function loadVideosParallel(videoIds) {
Promise.all(
videoIds.map(id => db.child('videos').child(id).once('value'))
);
}
Для сравнения: последовательная загрузка 64 элементов занимает 3,8 секунды в моей системе, а при загрузке их конвейерно (так как клиент Firebase выполняется изначально) требуется 600 мс. Точные цифры будут зависеть от вашего соединения (латентность и пропускная способность), но конвейерная версия всегда должна быть значительно быстрее.