簡體   English   中英

帶有firebase計時問題的javascript

[英]javascript with firebase timing issue

當我運行這段代碼時,我希望將final數組添加到firestore-> sendGrid集合中,但是它始終為空,盡管當我打印它時,它實際上具有值。

我相信這是因為時間問題,我總是得到[] -> 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);
  });
}

一些要點:(如果不確定原因,則使用Google)

- 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM