Данные загружаются из Firestore асинхронно. Остальная часть вашего кода продолжает выполняться, пока загружаются данные, и затем ваш обратный вызов then
вызывается, как только данные появляются.
Проще всего это увидеть с помощью нескольких правильно расположенных операторов журнала:
console.log("Starting to load data");
docRef.get().then(function (doc) {
console.log("Got data");
});
console.log("Started to load data");
Когда вы запускаете это, он печатает:
Начало загрузки данных [ 1126]
Начата загрузка данных
Получены данные
blockquote>Вероятно, это не тот результат, который вы ожидали, но он полностью объясняет поведение, которое вы видите. Прямо сейчас ваш
return store
запускает передstore = doc.data()
, что объясняет, почему вы не получаете желаемый результат.Это означает, что любой код, которому нужны данные, должен находиться внутри обратного вызова
then()
. Поэтому, если вы переместите вызов наsetState()
сразу послеstore = doc.data()
, он будет работать:docRef.get().then(function (doc) { if (doc.exists) { store = doc.data(); this.setState({name: store}); } else { // doc.data() will be undefined in this case console.log("No such document!"); } })
В качестве альтернативы, вы можете вернуть значение из
then()
вверх. В этом случае вам также понадобитсяthen()
в вашем коде вызова:function collectres () { var docRef = db.collection("cities").doc("SF"); return docRef.get() .then(function (doc) { if (doc.exists) { return doc.data(); } else { // doc.data() will be undefined in this case console.log("No such document!"); } }) .catch(function (error) { console.log("Error getting document:", error); }); }
И затем вызовите его с помощью:
Random() { let a = ''; user.collectres().then(function(a) { this.setState({name:a}); }); }
Асинхронные API чрезвычайно распространены в Современное программирование, поэтому я настоятельно рекомендую прочитать их. Для получения дополнительной информации см .:
В принципе, когда модуль выходит из области видимости, переменные этого модуля становятся неопределенными - если они не объявлены с атрибутом SAVE или не используется инструкция SAVE. «Не определено» означает, что вы не можете полагаться на переменную, имеющую предыдущее значение, если вы снова используете модуль - он может иметь прежнее значение при повторном доступе к модулю, или он может не иметь - нет гарантии , Но многие компиляторы не делают этого для переменных module - переменные, вероятно, сохраняют свои значения - компилятору не стоит пытаться выяснить, остается ли модуль в области действия или нет, и, вероятно, переменные модуля рассматриваются как глобальные переменные - но не полагайтесь на это! Чтобы быть в безопасности, либо используйте «сохранить», либо «используйте» модуль из основной программы, чтобы он никогда не выходил за рамки.
«save» также важно в процедурах, чтобы сохранить «state» между вызовами подпрограммы или функции (как написано @ire_and_curses) - инициализациями «first invocation», счетчиками и т. Д.
subroutine my_sub (y)
integer :: var
integer, save :: counter = 0
logical, save :: FirstCall = .TRUE.
counter = counter + 1
write (*, *) counter
if (FirstCall) then
FirstCall = .FALSE.
....
end if
var = ....
и т. Д.
В этом фрагменте кода «counter» сообщит о количестве вызовов подпрограммы x. Хотя на самом деле в Fortran> = 90 можно пропустить «save», потому что инициализация в объявлении подразумевает «save».
В отличие от случая модуля, в современных компиляторах без атрибута save или объявления инициализации по объявлению локальные переменные процедур обычно теряют свои значения при вызовах. Поэтому, если вы попытаетесь использовать «var» в последующем вызове, прежде чем переопределять его в этом вызове, значение будет неопределенным и, вероятно, не будет значением, рассчитанным при предыдущем вызове процедуры.
Это отличается от поведения многих компиляторов FORTRAN 77, некоторые из которых сохранили значения всех локальных переменных, хотя это не требовалось языковым стандартом. Некоторые старые программы были написаны с учетом этого нестандартного поведения - эти программы не будут работать на новых компиляторах. Многие компиляторы имеют возможность использовать нестандартное поведение и «сохранять» все локальные переменные.
LATER EDIT: обновление с примером кода, который показывает некорректное использование локальной переменной, которая должна иметь атрибут сохранения, но не имеет:
module subs
contains
subroutine asub (i, control)
implicit none
integer, intent (in) :: i
logical, intent (in) :: control
integer, save :: j = 0
integer :: k
j = j + i
if ( control ) k = 0
k = k + i
write (*, *) 'i, j, k=', i, j, k
end subroutine asub
end module subs
program test_saves
use subs
implicit none
call asub ( 3, .TRUE. )
call asub ( 4, .FALSE. )
end program test_saves
Локальная переменная k подпрограммы преднамеренно неправильно используется - в этой программе она инициализируется при первом вызове, поскольку control равен TRUE, но при втором вызове control равен FALSE, поэтому k не переопределено. Но без атрибута save k не определено, поэтому использование его значения недопустимо.
Скомпилировав программу с помощью gfortran, я обнаружил, что k все равно сохранил свое значение:
i, j, k= 3 3 3
i, j, k= 4 7 7
Скомпилировав программу с опциями ifort и агрессивной оптимизации, k потерял свое значение:
i, j, k= 3 3 3
i, j, k= 4 7 4
При использовании ifort с опциями отладки проблемы были обнаружены во время выполнения!
i, j, k= 3 3 3
forrtl: severe (193): Run-Time Check Failure. The variable 'subs_mp_asub_$K' is being used without being defined
Краткое объяснение может быть следующим: атрибут save
говорит, что значение переменной должно сохраняться при разных вызовах одной и той же подпрограммы / функции. В противном случае обычно, когда вы возвращаетесь из подпрограммы / функции, «локальные» переменные теряют свои значения, так как память, в которой хранились эти переменные, освобождается. Это как static
в Си, если вы знаете этот язык.
Обычно локальные переменные выходят из области видимости после того, как выполнение завершает текущую процедуру, и поэтому не имеют «памяти» своего значения при предыдущих вызовах. SAVE
- это способ указать, что переменная в процедуре должна сохранять свое значение от одного вызова до следующего. Это полезно, когда вы хотите сохранить состояние в процедуре, например, чтобы сохранить текущую сумму или сохранить конфигурацию переменной.
Здесь есть хорошее объяснение с примером.