Home > Software engineering >  why nested async/await doesn't work as intended?
why nested async/await doesn't work as intended?

Time:02-27

I'm learning NodeJs and having some problems using async/ await. I'm using Firebase database to read/write data. Here what i'm doing. (full function in case you need it).

async getImport(reqData: any): Promise<any> {
    const username = 'kdat0310';
    const db = admin.database();
    const userRef = db.ref('/user');
    const importRef = db.ref('/import');
    const refAuthentication = db.ref('/Authentication');
    const keyList = [];
    const providerKey = [];
    const khoList = [];
    let index = 0;
    const providerList = [];
    const isValid = await refAuthentication.once('value', function (snapshot) {
      for (const val of Object.values(snapshot.val())) {
        if (
          Object(val).username === Object(reqData).username &&
          Object(val).token === Object(reqData).token
        ) {
          return true;
        }
      }
      return false;
    });
    if (isValid) {
      await userRef.once('value', function (snapshot) {
        for (const value of Object.values(snapshot.val())) {
          if (value) {
            if (Object(value).username == username) {
              for (const val of Object(value).workAt) {
                if (val) khoList.push(val.khoId);
              }
            }
          }
        }
      });
      const typeAndColorKey = [];
      const typeAndColorValue = [];
      const typeAndColorRef = db.ref('/TypeAndColor');
      await typeAndColorRef.once('value', function (snapshot) {
        let count = 0;
        for (const key in snapshot.val()) {
          typeAndColorKey.push(key);
        }
        for (const value of snapshot.val()) {
          if (value !== undefined && value != null) {
            typeAndColorValue.push({
              id: typeAndColorKey[count],
              type: value.type,
              color: value.color,
            });
            count = count   1;
          }
        }
      });
      const findTypeAndColor = (id: any) => {
        for (const value of typeAndColorValue) {
          if (id == value.id) {
            return { type: value.type, color: value.color };
          }
        }
      };
      const userKey = [];
      const userList = [];
      await userRef.once('value', function (snapshot) {
        let count = 0;
        for (const key in snapshot.val()) {
          userKey.push(key);
        }
        for (const value of Object(snapshot.val())) {
          if (value != undefined && value != null) {
            userList.push({
              id: userKey[count],
              name: Object(value).name,
            });
            count  ;
          }
        }
      });
      const findUserName = (userId: any) => {
        const returnValue = '';
        for (const value of userList) {
          if (userId == Object(value).id) {
            return Object(value).name;
          }
        }
      };
      const importList = [];
      await importRef.once('value', async function (snapshot) {
        const importKey = [];
        const cloneArr = snapshot.val().map((item: any) => {
          return item;
        });
        for (const key in snapshot.val()) {
          importKey.push(key);
        }
        let countTemp = 0;
        for (const value of Object.values(cloneArr)) {
          const goodsKeyList = [];
          let count = 0;

          if (khoList.indexOf(Object(value).warehouseId) !== -1) {
            const listGoodsList = [];
            if (Object(value).listGoods) {
              for (const key in Object(value).listGoods) {
                goodsKeyList.push(key);
              }
              const refListGoods = db.ref(
                '/import/'   importKey[countTemp]   '/listGoods',
              );

              await refListGoods.once('value', function (snapshot) {
                let item: any;
                for (item of Object.values(snapshot.val())) {
                  if (item) {
                    const tempItem = item.filter((n: any) => n);
                    listGoodsList.push({
                      typeAndColor: findTypeAndColor(goodsKeyList[count]),
                      listGoods: tempItem,
                      number: tempItem.length,
                    });
                  }
                  count  ;
                }
              });
            }
            console.log('test 1', listGoodsList);
            if (listGoodsList !== []) {
              importList.push({
                listGoods: listGoodsList,
                driver: Object(value).driver,
                userId: Object(value).importEmployee,
                name: findUserName(Object(value).importEmployee),
                orderId: Object(value).orderId,
                warehouseId: Object(value).warehouseId,
                time: Object(value).time,
              });
            }
          }
          countTemp  ;
        }
        console.log('test 2', importList);
      });

      return importList;
    }
    return 'Invalid';
  }

The problem show up when it came to await importRef.once When I tried to handle some data and add the Firebase once function "async" and await inside to push the data I need to the array. Then return importList; return nothing. I figure that the await refListGoods.once cause this problems. As i thought, the await inside had done its duty and I can console.log importList inside very well. But I thought that await importRef.once will finish before return too. when I delete await refListGoods.once, the return is fine but I dont get the data I need. Do I need to refactor all code as I do to findTypeAndColor and findUserName above or there's a better way to solve this problem?

CodePudding user response:

If you want to use await on the Promise returned by once, you should not pass a callback function to it.

So instead of:

const isValid = await refAuthentication.once('value', function (snapshot) {
  for (const val of Object.values(snapshot.val())) {
    if (
      Object(val).username === Object(reqData).username &&
      Object(val).token === Object(reqData).token
    ) {
      return true;
    }
  }
  return false;
});

Do:

const snapshot = await refAuthentication.once('value');
let isValid = false;
snapshot.forEach((child) => {
  const val = child.val();
  if (val.username === Object(reqData).username &&
      val.token === Object(reqData).token
  ) {
    isValid = true;
  }
})
  • Related