Использование данных, возвращенных из Firebase fetch Javascript

Начинающий веб-разработчик здесь. Я использую Firebase в качестве бэкэнда, и у меня есть ситуация, когда мне нужно запросить БД для одного значения и использовать это возвращаемое значение для сопоставления в другом запросе к той же БД.

Вот мой код:

function dataLoad() {

    var valueThatINeedToUseElsewhere

    userReference.on('value',function(users){
        var currentUser = firebase.auth().currentUser.uid
        users.forEach(function(user){
            if (user.key === currentUser) {
                valueThatINeedToUseElsewhere = user.val().userName
                console.info(valueThatINeedToUseElsewhere)
            }
        })
    })
    console.info(valueThatINeedToUseElsewhere)
}

В console.info в условии IF записывается правильное значение. Однако последний из приведенных выше console.info ничего не регистрирует, несмотря на то, что имя переменной объявлено вне функции 'on'. Почему это происходит? И как я могу на самом деле использовать данные вне функции включения? Мне нужно использовать его для выполнения аналогичного условия IF в другой операции извлечения данных.

Спасибо!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
56
2

Ответы 2

on () является асинхронным и немедленно возвращается, что означает, что в журнале консоли будет отображаться неопределенное значение. Обратный вызов, который вы передаете on (), будет запущен только тогда, когда будут доступны результаты, и нет гарантии, как быстро это произойдет. Вы должны использовать значение из асинхронного вызова только после его завершения - не пытайтесь создать блок кода, пока не будет завершен какой-либо асинхронный вызов.

Также рассмотрите возможность использования once () вместо on (), если вам нужно значение в определенном месте только один раз. Вы можете использовать его возвращенное обещание, чтобы связать некоторую дополнительную работу после того, как он загрузит нужные данные. Он также является асинхронным (как и все другие методы, возвращающие обещание).

Чтобы узнать больше о том, почему API Firebase асинхронны и что это означает для вашего приложения, прочитай этот блог.

спасибо за быстрый ответ, Дуг - я пробовал использовать once (), но это действительно сбивало с толку. Сможете ли вы переписать указанную выше функцию примерно с помощью once () вместо on ()?

RefinedRascal 16.04.2018 02:55

Скорее всего, вы сейчас пытаетесь сделать что-то вроде этого:

var valueThatINeedToUseElsewhere;
dataLoad();
doSomethingWith(valueThatINeedToUseElsewhere);

К сожалению, это не работает, поскольку (как говорит Дуг) данные загружаются из Firebase асинхронно. К тому времени, когда вы пытаетесь использовать valueThatINeedToUseElsewhere, значение еще не загружено.

Почему это не работает, тест один-три-два

Проще всего в этом убедиться, если вы разместите несколько таких операторов журнала:

console.info("Before starting to load value")
userReference.on('value',function(users){
    console.info("Loaded value")
})
console.info("After starting to load value")

Когда вы запускаете этот код, он печатает:

Before starting to load value

After starting to load value

Loaded value

Вероятно, это не тот порядок, которого вы ожидали. Но это прекрасно объясняет, почему вы не можете использоватьvalueThatINeedToUseElsewhere при попытке: он еще не загружен.

Переосмысление проблемы

Лучший способ справиться с этой ситуацией, который я нашел, - это переосмыслить проблему. Ваш текущий код написан с логикой «сначала мы загружаем значение, затем мы что-то делаем со значением». Для асинхронной загрузки лучше оформить это как «сначала начните загрузку данных. Как только данные начали загружаться, сделайте с ними что-нибудь».

В коде, который выглядит так:

function dataLoad() {
    userReference.once('value',function(users){
        var currentUser = firebase.auth().currentUser.uid
        users.forEach(function(user){
            if (user.key === currentUser) {
                var valueThatINeedToUseElsewhere = user.val().userName
                doSomethingWith(valueThatINeedToUseElsewhere)
            }
        })
    })
}

Как вы увидите, мы переместили код, которому нужны данные. в - обратный вызов, который запускается, когда данные доступны. Таким образом, вы можете быть уверены, что данные доступны при звонке в doSomethingWith. Я также изменил код, чтобы использовать once, что (как сказал Дуг) лучше для вашего варианта использования.

Необходимо предпринять еще два шага, чтобы повысить гибкость и производительность вашего кода.

Передавая функцию, которая называется однажды, данные загружаются

Во-первых: в этом последнем обновлении вызов doSomethingWith жестко запрограммирован, что означает, что dataLoad() и doSomethingWith тесно связаны друг с другом. Часто лучше держать их подальше друг от друга. Для этого мы можем передать так называемую функцию обратного вызова в dataLoad, которую он затем вызывает, когда загружает данные. Это очень аналогично тому, что уже делает once(). Посмотрим на это на практике:

function dataLoad(callback) {
    userReference.once('value',function(users){
        var currentUser = firebase.auth().currentUser.uid
        users.forEach(function(user){
            if (user.key === currentUser) {
                var valueThatINeedToUseElsewhere = user.val().userName
                callback(valueThatINeedToUseElsewhere)
            }
        })
    })
}

Не слишком разные. Но теперь вы можете вызвать dataLoad следующим образом:

dataLoad(doSomethingWith);

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

Загрузка данных по ключу

Последнее изменение - оптимизация. Ваш текущий код загружает всех пользователей, а вам нужен только один и вы знаете их ключ. Гораздо эффективнее загружать только этого конкретного пользователя с помощью:

function dataLoad(callback) {
    var currentUser = firebase.auth().currentUser.uid
    userReference.child(currentUser).once('value',function(users){
        var valueThatINeedToUseElsewhere = user.val().userName
        callback(valueThatINeedToUseElsewhere)
    })
}

Ух ты! Спасибо за невероятно подробный ответ, Фрэнк! Просматривая пост Дуга на Medium, я понял, что моя проблема - 1,3,2. Ваш метод решает это правильно - плюс тот факт, что вы получаете ровно одного пользователя, идеально. Однако обратный вызов на самом деле является еще одним запросом к базе данных, который мне нужно выполнить. И снова, это будет возвращение одного значения, как указано выше. Я не уверен, как написать обратный вызов для другого удаления данных из Firebase. Не могли бы вы пролить свет на это?

RefinedRascal 16.04.2018 03:32

Думаю, я разобрался. Я отвечу здесь своим решением, как только оно заработает. Еще раз спасибо за отличный ответ!

RefinedRascal 16.04.2018 03:37

Другие вопросы по теме