Здравствуйте, у меня есть некоторые проблемы с функциями Firebase, но проблема, скорее всего, больше связана с JavaScript. Вы видите, мне нужна функция для возврата клиенту массива объектов, которые находятся в пределах диапазона местоположения клиента. Проблема заключается в том, что этой функции необходимо выполнить итерации и протестировать документы в коллекции, чтобы увидеть, находятся ли они в пределах досягаемости. Если это так, поместите объект в массив. Как только он завершит итерацию каждой вещи, верните массив обратно клиенту.
Основная проблема заключается в том, что JavaScript не работает синхронно, когда дело доходит до циклов. Поэтому моей следующей идеей было попытаться заставить ожидание после завершения итерации, используя обещания. Ниже приведен код, который у меня есть:
export const getNearbyBison = functions.https.onCall((data, context) => {
let distance = data.distance;
let thisUid = data.uid;
let Lat1 = data.x;
let Lon1 = data.y;
let returnUIDs: any[] = [];
console.log(distance, thisUid, Lat1, Lon1);
var needDocs = admin.firestore().collection('users').doc('user').collection('user').where('locationEnabled', '==', true).get();
return needDocs.then(documents => {
console.log(documents);
let theseDocs = documents.docs;
let promiseCheck: any[] = [];
theseDocs.forEach(doc => {
let pUid = doc.data().uid;
console.log('Uid of this user' + pUid);
admin.firestore().collection('location').doc(pUid).get().then(async location => {
if (location.exists) {
console.log('Location of this user' + location);
let locID = location.id;
let thisData = location.data();
let Lat2 = thisData!.x;
let Lon2 = thisData!.y;
console.log(locID, Lat2, Lon2);
//**********Location equation to solve distance*********
var R = 6371000;
var phi1 = Lat1 * Math.PI / 180;
var phi2 = Lat2 * Math.PI / 180;
var deltaPhi = Lat2 - Lat1;
var deltaLambda = Lon2 - Lon1;
var dLat = deltaPhi * Math.PI / 180;
var dLon = deltaLambda * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(phi1) * Math.cos(phi2) * Math.sin(dLon / 2) *
Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
//*******Convert to miles**************
var miles = d / 1609.34;
console.log('Miles of user: ' + miles);
let pusher = new Promise((resolve, reject) => {
if (miles <= distance) {
if (thisUid != locID) {
//Remember this setup for when you have to use the info for this page...
returnUIDs.push({
farAway: miles,
userInfo: doc
});
resolve();
} else { resolve() }
} else { resolve() }
});
promiseCheck.push(
pusher
)
}
}).catch();
})
Promise.all(promiseCheck).then(whatever => {
console.log(returnUIDs);
return ({
nearbyArray: returnUIDs
});
}).catch();
}).catch();
});
Проблема в том, что функция все еще отправляет массив клиенту до того, как цикл forEach завершит итерацию. Есть ли способ заставить его ждать? Что я делаю неправильно? Я рассмотрел другие подобные проблемы на этом форуме, и вот как я пришел к выводу, что мне нужно каким-то образом использовать Promises, чтобы заставить программу ждать завершения цикла. Заранее спасибо.
Редактировать :: Хорошо, так что я добился значительного прогресса. Во-первых, я помещаю все, что находится внутри цикла forEach (), в возвращаемое обещание, а затем помещаю каждое из них в массив Promise. Я посмотрел, как Javascript работает с асинхронными операциями, и это было причиной, по которой он записывал пустой массив на мою консоль до завершения циклов. Я проверил свою консоль, и теперь она регистрирует возвращенный массив ПОСЛЕ окончания цикла forEach. Вот отредактированный код:
export const getNearbyBison = functions.https.onCall((data, context) => {
let distance = data.distance;
let thisUid = data.uid;
let Lat1 = data.x;
let Lon1 = data.y;
let returnUIDs: any[] = [];
console.log(distance, thisUid, Lat1, Lon1);
var needDocs = admin.firestore().collection('users').doc('user').collection('user').where('locationEnabled', '==', true).get();
needDocs.then(documents => {
console.log(documents);
let theseDocs = documents.docs;
let promiseCheck: any[] = [];
theseDocs.forEach(doc => {
let pusher = new Promise((resolve, reject) => {
let pUid = doc.data().uid;
console.log('Uid of this user' + pUid);
admin.firestore().collection('location').doc(pUid).get().then(location => {
if (location.exists) {
console.log('Location of this user' + location);
let locID = location.id;
let thisData = location.data();
let Lat2 = thisData!.x;
let Lon2 = thisData!.y;
console.log(locID, Lat2, Lon2);
//**********Location equation to solve distance*********
var R = 6371000;
var phi1 = Lat1 * Math.PI / 180;
var phi2 = Lat2 * Math.PI / 180;
var deltaPhi = Lat2 - Lat1;
var deltaLambda = Lon2 - Lon1;
var dLat = deltaPhi * Math.PI / 180;
var dLon = deltaLambda * Math.PI / 180;
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(phi1) * Math.cos(phi2) * Math.sin(dLon / 2) *
Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
//*******Convert to miles**************
var miles = d / 1609.34;
console.log('Miles of user: ' + miles);
if (miles <= distance) {
if (thisUid != locID) {
//Remember this setup for when you have to use the info for this page...
returnUIDs.push({
farAway: miles,
userInfo: doc
});
resolve();
} else { resolve() }
} else { resolve() }
}
}).catch();
});
promiseCheck.push(pusher);
});
Promise.all(promiseCheck).then(whatever => {
console.log(returnUIDs);
return ({
nearbyArray: returnUIDs
});
}).catch();
}).catch();
});
Проблема теперь в том, что ЕЩЕ все равно возвращает пустую информацию клиенту. Не только это, но и эта пустая информация отправляется до завершения цикла. Итак, на моей консоли я вижу, что массив, который должна возвращать функция, заполнен правильной информацией для отправки обратно. Проблема, однако, в том, что функция по-прежнему ничего не отправляет, я подозреваю, потому что она все еще отправляет до завершения цикла. Может кто-нибудь сказать мне, почему это так?