Короткий ответ: объем переменных не является проблемой. В Javascript var
ограничен окружающей функцией. В приведенном примере кода forEach
передается function
, поэтому все его переменные имеют область видимости, объявленную. Внешние переменные фиксируются во внутренней функции, поэтому они также ведут себя правильно.
Проблема в том, что внутренний promise
не разрешается до того, как switchmap
вернет значение.
Чтобы полностью понять, что происходит, давайте посмотрим, что в данный момент делает код и что он должен делать вместо этого.
Ради аргумента я собираюсь принять следующие определения (хотя я знаю, что они не верны):
selectedUserMessages : Observable<[]>;
changeUserList : Observable<String>;
Здесь changeUserList
- это поток строковых событий, представляющий текущий выбранный UserId
. selectedUserMessages
будет массивом сообщений, связанных с выбранным пользователем.
Код выше упрощен до следующего значения:
this.selectedUserMessages =
// when changeUserList changes, switch selectedUserMessages to this new stream
this.changeUserList.switchMap(Userid => {
if (Userid) {
// grab DB reference to user child list
var ref = db.database.ref(`wfffsdf/usesdfdsfsrs/${Userid}/ress`);
// CREATE A PROMISE TO QUERY THE DATABASE
ref.once("value") // query once
.then(function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var key = childSnapshot.key;
var val = childSnapshot.val();
// process child
});
// store result
this.chatMessages = this.getMessages(this.ChatKey);
}); // END OF PROMISE
// RETURN IMMEDIATELY, BEFORE PROMISE RESOLVES
return this.chatMessages;
}
return of(null); // return null stream
}
Проблема в том, что вызов switchmap возвращает this.chatMessages
до разрешения внутреннего обещания.
switchmap
имеет интересную особенность: вы можете вернуть обещание изнутри карты-переключателя, и оно будет ждать обещания. Это один из способов смешать Обещания и Observables .
Возвращение обещания из карты переключений выглядит следующим образом:
this.selectedUserMessages =
// when changeUserList changes, switch selectedUserMessages to this new stream
this.changeUserList.switchMap(Userid => {
if (Userid) {
// grab DB reference to user child list
let ref = db.database.ref(`wfffsdf/usesdfdsfsrs/${Userid}/ress`);
// !!!! RETURN A PROMISE TO QUERY THE DATABASE !!!!
return ref.once("value") // query once
.then(function (snapshot) {
let results = [];
snapshot.forEach(function (childSnapshot) {
let key = childSnapshot.key;
let val = childSnapshot.val();
// process child //
results.push(/*processing results*/);
});
return results;
}); // END OF PROMISE
}
else
return of(null); // return null stream
}
С учетом вышесказанного, существует альтернатива смешиванию Promises и Observables для Firebase под названием RxFire . Это относительно новый пакет от команды Firebase для использования RxJS Observables. Поскольку вы используете базу данных реального времени, вам нужно посмотреть на эти примеры . List () будет генерировать поток дочерних изменений. Вы можете pipe()
этот поток через оператор map()
, чтобы выполнить дополнительную обработку (или извлечь val () и включить ключ, как в примере). то, что вы делаете в map (), похоже на то, что вы делаете в forEach
.
AngularFirebase содержит пример использования RxFire в FireStore.