gpt4 book ai didi

javascript - Firebase 函数如何在循环完成迭代后发送

转载 作者:行者123 更新时间:2023-11-28 03:25:23 25 4
gpt4 key购买 nike

您好,我在使用 Firebase Functions 时遇到了一些问题,但问题很可能更多发生在 JavaScript 方面。您会看到,我需要一个函数来向客户端返回客户端位置范围内的对象数组。问题在于该函数需要迭代并测试集合中的文档以查看它们是否在范围内。如果是,则将对象插入数组。一旦完成迭代每个事物,将数组返回给客户端。

主要问题是 JavaScript 在循环方面不是同步的。所以我的下一个想法是尝试使用 Promise 在迭代完成后强制等待。下面是我目前拥有的代码:

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 中,然后将每个内容推送到 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();

});

现在的问题是它仍然向客户端返回空信息。不仅如此,这些空信息还在循环完成之前发送。因此,在我的控制台上,我可以看到函数应返回的数组填充了要发回的正确信息。然而问题是该函数仍然没有发送任何内容,我怀疑是因为它仍在循环完成之前发送。谁能告诉我为什么会这样?

最佳答案

好的,伙计们,我知道问题出在哪里了!每当您希望 Firebase 函数在异步操作后返回时,您都必须返回 Promise。因此,在上面的代码中,每次执行异步操作时,我都必须将 return 放在它前面。不仅如此,我还必须将所有内容一个接一个地嵌套在 .then() 函数中。这不是最简单的任务,因为当您处理需要大量异步操作的大量代码时,很容易在代码中迷失方向。但这就是 Firebase 的工作原理(或 Google 云功能,两者之一)。也许它们将来会让执行异步功能变得更容易,但这是主要问题。在下面的代码中,您可以看到每个异步函数都被返回,并且代码的所有主要部分都位于前一个函数的 .then() 中。

我确实注意到它可以简化一点,因为虽然 Promise 是一个重要的部分,但它们并不是代码的主要问题。问题在于 Firebase(或 Google)如何处理异步代码。

export const getNearbyBison = functions.https.onCall((data, context) => {
let counter = 0;
let distance = data.distance;
let thisUid = data.uid;
let Lat1 = data.x;
let Lon1 = data.y;
let returnUIDs: any[] = [];
let promiseCheck: 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 => {
return new Promise((r, j) => {
console.log(documents);
let theseDocs = documents.docs;

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
});
counter++;
resolve();
} else {
counter++;
resolve();
}
} else {
counter++;
resolve();
}
if (counter >= documents.size) {
r();
}

}
}).catch();
});
promiseCheck.push(pusher);
});

}).then(() => {
return Promise.all(promiseCheck).then(whatever => {
console.log(returnUIDs);
return { nearbyArray: returnUIDs };
}).catch();
}).catch();
}).catch();

});

正如你所看到的,持续不断的雏鸟可能会让人不知所措,但目前这是一种必要的罪恶,也许将来这种情况会改变,以便更优雅地处理。

关于javascript - Firebase 函数如何在循环完成迭代后发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58674018/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com