Javascript 使用firebase调用时如何在forEach内部使用异步调用
我的问题是,我不知道如何使用Firestore使这段代码正常工作(不确定这是否无关) 实际代码如下所示:Javascript 使用firebase调用时如何在forEach内部使用异步调用,javascript,vue.js,asynchronous,vuejs2,Javascript,Vue.js,Asynchronous,Vuejs2,我的问题是,我不知道如何使用Firestore使这段代码正常工作(不确定这是否无关) 实际代码如下所示: prestamoItems() { var myarray = []; var myobject = {}; //here comes the first async method (works OK) fb.prestamosCollection .orderBy("fechaPrestamo", "desc")
prestamoItems() {
var myarray = [];
var myobject = {};
//here comes the first async method (works OK)
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
//here comes forEach
val.docs.forEach(doc => {
myobject = doc.data();
myobject.id = doc.id;
console.log("The doc id is " +myobject.id)
//here comes second async call inside the forEach loop, but it doesnt wait for this
//to be finished, and immediately goes to the other step
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
})
myarray.push(myobject)
console.log("myobject pushed to myarray")
});
}
});
}
11:13:14.999 Prestamos.vue?18d2:71 The doc id is 1yTCUKwBvlopXX2suvVu
11:13:14.999 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is Z5TE15Fj3HFrn1zvceGe
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is JNN9aN65XE1tUTmlzkoJ
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is NF2hHCpM8leZezHbmnJx
11:13:15.001 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.364 Prestamos.vue?18d2:74 The doc id from the other collection is 1yTCUKwBvlopXX2suvVu
11:13:15.368 Prestamos.vue?18d2:74 The doc id from the other collection is Z5TE15Fj3HFrn1zvceGe
11:13:15.374 Prestamos.vue?18d2:74 The doc id from the other collection is JNN9aN65XE1tUTmlzkoJ
11:13:15.379 Prestamos.vue?18d2:74 The doc id from the other collection is NF2hHCpM8leZezHbmnJx
请注意,我在来自另一个异步方法的forEach循环中调用一个异步方法。在代码的每个变体中,我得到的输出(控制台日志)如下所示:
prestamoItems() {
var myarray = [];
var myobject = {};
//here comes the first async method (works OK)
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
//here comes forEach
val.docs.forEach(doc => {
myobject = doc.data();
myobject.id = doc.id;
console.log("The doc id is " +myobject.id)
//here comes second async call inside the forEach loop, but it doesnt wait for this
//to be finished, and immediately goes to the other step
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
})
myarray.push(myobject)
console.log("myobject pushed to myarray")
});
}
});
}
11:13:14.999 Prestamos.vue?18d2:71 The doc id is 1yTCUKwBvlopXX2suvVu
11:13:14.999 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is Z5TE15Fj3HFrn1zvceGe
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is JNN9aN65XE1tUTmlzkoJ
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is NF2hHCpM8leZezHbmnJx
11:13:15.001 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.364 Prestamos.vue?18d2:74 The doc id from the other collection is 1yTCUKwBvlopXX2suvVu
11:13:15.368 Prestamos.vue?18d2:74 The doc id from the other collection is Z5TE15Fj3HFrn1zvceGe
11:13:15.374 Prestamos.vue?18d2:74 The doc id from the other collection is JNN9aN65XE1tUTmlzkoJ
11:13:15.379 Prestamos.vue?18d2:74 The doc id from the other collection is NF2hHCpM8leZezHbmnJx
因此,forEach循环没有等待内部的异步函数(这实际上是预期的行为,AFAIK)
问题是如何让它在将对象添加到数组之前等待内部调用完成?提前谢谢。只需像这样向内推动即可
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
myarray.push(myobject)
console.log("myobject pushed to myarray")
})
就这样往里推
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
myarray.push(myobject)
console.log("myobject pushed to myarray")
})
要么将依赖于先前结果的代码嵌套到
then()
回调中,要么将循环(forEach
不支持异步)包装在async
块中,以利用wait
内部。例如:
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
// wrap loop in async function call iife so we can use await inside
(async () => {
for (var i = 0; i < val.docs.length; i++) {
const doc = val.docs[i];
myobject = doc.data();
myobject.id = doc.id;
// this will be synchronous now
let eqp = await fb.equiposCollection.doc(myobject.id).get();
console.log(eqp.id);
myarray.push(myobject)
}
})();
}
});
fb.prestamosCollection
.orderBy(“fechaPrestamo”、“desc”)
.get()
.然后(val=>{
如果(!val.empty){
//在异步函数调用iife中包装循环,以便在内部使用wait
(异步()=>{
对于(var i=0;i
要么将依赖于先前结果的代码嵌套到then()
回调中,要么将循环(forEach
不支持异步)包装在async
块中,以便在内部使用wait
。例如:
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
// wrap loop in async function call iife so we can use await inside
(async () => {
for (var i = 0; i < val.docs.length; i++) {
const doc = val.docs[i];
myobject = doc.data();
myobject.id = doc.id;
// this will be synchronous now
let eqp = await fb.equiposCollection.doc(myobject.id).get();
console.log(eqp.id);
myarray.push(myobject)
}
})();
}
});
fb.prestamosCollection
.orderBy(“fechaPrestamo”、“desc”)
.get()
.然后(val=>{
如果(!val.empty){
//在异步函数调用iife中包装循环,以便在内部使用wait
(异步()=>{
对于(var i=0;i
问题的根源在于,您试图将非同步操作(等待Firestore返回值)转变为同步操作。在JavaScript中,如果不引起很多问题,这是不可能以有意义的方式实现的
您需要在.then()
回调中填充数组,并作为函数的结果返回承诺。调用prestamoItems()
函数的任何调用方也必须使用。然后()
回调以访问底层myarray
值:
const _ = {
async prestamoItems() {
const val = await fb.prestamosCollection.orderBy("fechaPrestamo", "desc").get();
if (val.empty) {
return myarray
}
// Promise.all() will take a list of promises and will return their results once they have all finished.
return await Promise.all(
// Array.prototype.map() will take an existing array and, for each item, call the given function and return a new array with the return value of each function in that array.
// This is functionally equivalent to making a new array and push()ing to it, but it reads a lot nicer!
val.docs.map(async doc => {
const myobject = doc.data();
const eqp = await fp.equiposCollection.doc(myobject.id).get()
// I presume you want to do something with eqp here
return myobject
})
);
}
}
上面的代码示例使用Array.prototype.map()
来删除myarray
,因为它不是必需的
调用者必须使用以下代码:
_.prestamoItems().then((myarray) => {
...
})
承诺是一种表示价值在未来某个时刻可能可用的方式。因此,您必须确保您与承诺的任何交互都是以这样一种方式编写的,即假定该值不是立即可用的。最简单的方法是使用
async
/wait
并确保返回承诺对象。问题的根源在于,您试图将非同步操作(等待Firestore返回值)转变为同步操作。在JavaScript中,如果不引起很多问题,这是不可能以有意义的方式实现的
您需要在.then()
回调中填充数组,并作为函数的结果返回承诺。调用prestamoItems()
函数的任何调用方也必须使用。然后()
回调以访问底层myarray
值:
const _ = {
async prestamoItems() {
const val = await fb.prestamosCollection.orderBy("fechaPrestamo", "desc").get();
if (val.empty) {
return myarray
}
// Promise.all() will take a list of promises and will return their results once they have all finished.
return await Promise.all(
// Array.prototype.map() will take an existing array and, for each item, call the given function and return a new array with the return value of each function in that array.
// This is functionally equivalent to making a new array and push()ing to it, but it reads a lot nicer!
val.docs.map(async doc => {
const myobject = doc.data();
const eqp = await fp.equiposCollection.doc(myobject.id).get()
// I presume you want to do something with eqp here
return myobject
})
);
}
}
上面的代码示例使用Array.prototype.map()
来删除myarray
,因为它不是必需的
调用者必须使用以下代码:
_.prestamoItems().then((myarray) => {
...
})
承诺是一种表示价值在未来某个时刻可能可用的方式。因此,您必须确保您与承诺的任何交互都是以这样一种方式编写的,即假定该值不是立即可用的。最简单的方法是使用
async
/wait
并确保返回承诺对象。将adding to数组放在then
中。仍然是相同的结果,即使在第二个then()OP中推送,我假设在将元素推送到myarray
之后,您打算使用它。您将如何使用它?在返回myarray后,我将把结果放在bootstrap vue表(b-table)中。将添加到中的数组放在中,然后
。仍然是相同的结果,即使在第二个then()OP中推送,我假设您打算在将元素推送到它之后使用myarray
。您将如何使用它?返回MyArray后,我将把结果放在bootstrap vue表(b表)中。这是一个很好的答案,但接受的答案具有更简单的结构。无论如何,谢谢你的帮助,我们非常感谢你的帮助。接受的答案也有不同的功能:它将按顺序从数据库中获取每个项目,而不是并行,因此速度会慢得多。我一直在使用接受的答案,你是对的,它将按顺序进行,因此它将比大型集合的预期速度慢得多(我现在有一个小集合,只是为了测试的目的)。我将修改我的代码,因为你认为这是一个好的答案,但是被接受的答案有一个更简单的结构。谢谢