Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
222 views
in Technique[技术] by (71.8m points)

javascript - Wait for nested loops to finish before returning in node

I am trying to push results from a thrice nested loop into a results array, and at the end return that array. I figured that having .then would achieve the behavior I'm looking for, but the function returns an empty array immediately. I have tried using variations of async/await, .map, and for loops with no luck.

exports.getMasterTenantList = functions.https.onRequest((req, res) => {
  let result = [];
  cors(req, res, () => {
    admin
      .database()
      .ref("/property_names")
      .once("value")
      .then((snapshot) => {
        snapshot.forEach((childSnapshot) => {
          const propertyName = childSnapshot.key;
          admin
            .database()
            .ref(`/property_groups/${propertyName}/locations`)
            .once("value")
            .then((addresses) => {
              return addresses.forEach((addressSnapshot) => {
                const address = addressSnapshot.key;
                admin
                  .database()
                  .ref(`/property_groups/${propertyName}/locations/${address}/residents`)
                  .once("value")
                  .then((residents) => {
                    return residents.forEach((resSnapshot) => {
                      result.push(resSnapshot.val().name);
                    });
                  })
                  .catch((error) => {
                    console.log(error);
                  });
              });
            })
            .catch((error) => {
              console.log(error);
            });
        });
        return res.status(200).send(result);
      })
      .catch((error) => {
        console.log(error);
      });
  });
});
question from:https://stackoverflow.com/questions/65939832/wait-for-nested-loops-to-finish-before-returning-in-node

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your mistake is that return addresses.forEach doesn't return what you think it does.

You should follow your code and wait for every requests to come back. You can use Promise.all for that.


I would go for something like this :

exports.getMasterTenantList = functions.https.onRequest(async(req, res) => {
  await cors(req, res);

  const snapshot = await admin
    .database()
    .ref('/property_names')
    .once('value');

  const result = await Promise.all(snapshot.forEach((childSnapshot) => {
    const propertyName = childSnapshot.key;

    const addresses = await admin
      .database()
      .ref(`/property_groups/${propertyName}/locations`)
      .once('value');

    return Promise.all(addresses.map(async(addressSnapshot) => {
      const address = addressSnapshot.key;

      const residents = await admin
        .database()
        .ref(`/property_groups/${propertyName}/locations/${address}/residents`)
        .once('value');

      return residents.map(resSnapshot => resSnapshot.val().name);
    }));
  }));

  return res.status(200).send(result);
});

To understand how it works look at the following snippet example :

const cors = () => new Promise((resolve) => setTimeout(resolve, 100));

const getSnapshot = () => new Promise((resolve) => setTimeout(() => {
  resolve([{
    key: 'dog',
  }]);
}, 100));

const getAddress = () => new Promise((resolve) => setTimeout(() => ?{
  resolve([{
    key: '11 richmond street',
  }]);
}, 100));

const getResident = () => new Promise((resolve) => setTimeout(() =>?{
  resolve([{
    val: () => ({
      name: 'John doe',
    }),
  }]);
}, 100));

async function onRequest(res) {
  await cors();

  const snapshot = await getSnapshot();

  const result = await Promise.all(snapshot.map(async (childSnapshot) => {
    const propertyName = childSnapshot.key;

    const addresses = await getAddress();

    return Promise.all(addresses.map(async(addressSnapshot) => {
      const address = addressSnapshot.key;

      const residents = await getResident();

      return residents.map(resSnapshot => resSnapshot.val().name);
    }));
  }));

  return res.status(200).send(result);
}

onRequest({
  status: () => ({
    send: console.log,
  }),
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...