带有 firebase 计时问题的 javascript

标签 javascript firebase google-cloud-firestore

当我运行这段代码时,我希望将数组 final 添加到 firestore -> sendGrid 集合中,但它始终是空的,尽管当我打印它时,它实际上有值(value)观。

我相信这是因为时间问题,我总是得到 [] -> value is just evaluated now (警告),当我展开它时它有值。

function test() {

  let today = new Date();
  let addedDate = new Date(today.addDays(7));
  let final = [];
  let counter = 0;
  let adder = new Promise(function (resolve, reject) {
  db.collection("email").get()
    .then((querySnapshot) => {
      console.log(querySnapshot);
      if (querySnapshot.empty !== true) {
        querySnapshot.forEach((data) => {
          console.log(data.data());
          console.log(data.id);
          let db2 = db.collection("email").doc(data.id);
          let foodArr = [];
          if (data.data() !== null) {
            console.log(addedDate);
            if (addedDate >= userList[0].exxpiaryDate) {
              console.log("True");
            }
            db2.collection("list").where("expiaryDate", "<", addedDate.getTime()).get()
              .then((list) => {
                if (list.empty !== true) {
                  list.forEach((food) => {
                  if (food !== null) {
                    let temp = {
                      name: food.data().name,
                      time: food.data().expiaryDate,
                    };
                    foodArr.push(temp);
                    console.log(foodArr);
                  }
                })
              }
              if (foodArr.length !== 0) {
                let emailArr = {
                  email: data.data().email,
                  food: foodArr
                };
                console.log(emailArr);
                final[counter] = (emailArr);
                counter++;
                console.log(final[0]);
              }
            }).catch((err) => {
              console.log(err);
            });
          }
        });
      }
      console.log(final);
      resolve(final);
    }).catch((err) => {
      console.log(err);
    });
  });
  return adder;
}

async function add() {
  let add = await test();
  console.log(add);
  db.collection("sendGrid").add({
    response: add
  }).then((item) => {
    console.log(item);
  }).catch((err) => {
    console.log(err);
  });
}

最佳答案

一些要点:(如果不确定原因请谷歌)

- prefer const
- return early
- clean code (eg. from console.log:s)
- cache fn calls
- functional programming is neat, look up Array.(map, filter, reduce, ...)
- destructuring is neat
- use arr[arr.length] = x; or arr.push(x), no need to manage your own counter
- short-circuit is sometimes neat (condition && expression; instead of if (condition) expression;)
- is queryResult.empty a thing? If it's a normal array, use !arr.length
- define variables in the inner most possible scope it's used in
- if having a promise in an async, make sure to return it
- prefer arrow functions

我更改了代码以遵循这些要点:

const test = ()=> {
  const today = new Date();
  const addedDate = new Date(today.addDays(7));

  return new Promise((resolve)=> {
    const final = [];
    const emailsQuery = db.collection("email")

    // an async/promise/then that's inside another promise, but not returned/awaited
    emailsQuery.get().then((querySnapshot) => {
      querySnapshot
        .map(data=> ({id: data.id, data: data.data()}))
        .filter(o=> o.data)
        .forEach(({id, data: {email}}) => {

        const db2 = db.collection("email").doc(id);
        const itemsQuery = db2.collection("list").where("expiaryDate", "<", addedDate.getTime())

        // another one!
        itemsQuery.get().then((items) => {
          const food = items.filter(o=> o).map(o=> o.data()).filter(o=> o)
            .forEach(({name, expiaryDate: time})=> ({name, time}))

          food.length && final.push({email, food})
        }).catch(console.error);
      });

      // resolving before the two async ones have finished!!
      resolve(final);
    }).catch(console.error);
  });
}

const add = async ()=> {
  let response = await test();
  return db.collection("sendGrid").add({response})
    .then((item) => console.log('item:', item))
    .catch(console.error)
}

现在,我们可以看到异步流程存在问题(用您的话说是“计时问题”)。我将再添加一个最佳实践:

- use async/await when possible

改变使用那个使它更清楚,并解决问题:

const test = async ()=> {
  const today = new Date();
  const addedDate = new Date(today.addDays(7));
  const emailsQuery = db.collection("email")
  const querySnapshot = await emailsQuery.get()
  const emailEntries = querySnapshot
    .map(data=> ({id: data.id, data: data.data()}))
    .filter(o=> o.data)

  // invoking an async fn -> promise; map returns the result of all invoked fns -> array of promises
  const promisedItems = emailEntries.map(async ({id, data: {email}}) => {
    const db2 = db.collection("email").doc(id);
    const itemsQuery = db2.collection("list").where("expiaryDate", "<", addedDate.getTime())

    const items = await itemsQuery.get()
    const food = items.filter(o=> o).map(o=> o.data()).filter(o=> o)
      .forEach(({name, expiaryDate: time})=> ({name, time}))

    return {email, food}
  });

  const items = await Promise.all(promisedItems)
  return items.filter(item=> item.food.length)
}

const add = async ()=> {
  let response = await test();
  return db.collection("sendGrid").add({response})
    .then((item) => console.log('item:', item))
    .catch(console.error)
}

现在,流程很清楚了!

.


更简洁(虽然缺少 var 名称 -> 不太清楚)- 只是为了好玩:

// (spelled-fixed expiryDate); down to 23% loc, 42% char
const getUnexpiredFoodPerEmails = async ({expiryDateMax} = {
  expiryDateMax: new Date(new Date().addDays(7)),
})=> (await Promise.all((await db.collection('email').get())
  .map(data=> ({id: data.id, data: data.data()})).filter(o=> o.data)
  .map(async ({id, data: {email}})=> ({
    email,
    food: (await db.collection('email').doc(id).collection('list')
      .where('expiryDate', '<', expiryDateMax.getTime()).get())
      .filter(o=> o).map(o=> o.data()).filter(o=> o)
      .forEach(({name, expiryDate: time})=> ({name, time})),
  }))
)).filter(item=> item.food.length)

const add = async ()=> db.collection('sendGrid').add({
  response: await getUnexpiredFoodPerEmails(),
}).then(console.log).catch(console.error)

// ...or with names
const getUnexpiredFoodListForEmailId = async ({id, expiryDateMax} = {
  expiryDateMax: new Date(new Date().addDays(7)),
})=> (await db.collection('email').doc(id).collection('list')
  .where('expiryDate', '<', expiryDateMax.getTime()).get())
  .filter(o=> o).map(o=> o.data()).filter(o=> o)
  .forEach(({name, expiryDate})=> ({name, time: expiryDate}))

const getEmails = async ()=> (await db.collection('email').get())
  .map(data=> ({id: data.id, data: data.data()})).filter(o=> o.data)

const getUnexpiredFoodPerEmails = async ({expiryDateMax} = {
})=> (await Promise.all((await getEmails()).map(async ({id, data})=> ({
  email: data.email,
  food: await getUnexpiredFoodListForEmailId({id, expiryDateMax}),
})))).filter(item=> item.food.length)


const add = async ()=> db.collection('sendGrid').add({
  response: await getUnexpiredFoodPerEmails(),
}).then(console.log).catch(console.error)

关于带有 firebase 计时问题的 javascript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50288394/

相关文章:

javascript - Node 返回 BluebirdJS Promise

javascript - 将 PHP 插入 jQuery css()

firebase - 当 native 应用程序为 "backgrounded"时,是否应该删除 Firebase 监听器?

javascript - 如何使用Javascript从该表中获取信息

ios - Xcode UI 未使用最新的 Firebase 值进行更新

javascript - 上传多个文件到 firebase 存储问题

firebase - 在 Flutter 中计算排行榜排名

swift - 从 Firestore 数据库检索数据时出现问题

javascript - 有关在 Firebase 云函数内部生成一致日期的问题

javascript - jQueryui Selectmenu - 保存值