1

In the following code:

  async createPanoramas ({ dispatch, commit, rootState }, newPanoramas = {}) {
    const { enterprise = '' } = rootState.route.query
    const splitNewPanoramas = []
    const clonedNewPanoramas = newPanoramas.panoramas.slice()

    while (clonedNewPanoramas.length) {
      splitNewPanoramas.push(clonedNewPanoramas.splice(0, MAX_ARRAY_EACH_API_CALL))
    }

    return splitNewPanoramas.forEach(async panoramasPayload => {
      const payload = {
        buildingId: newPanoramas.buildingId,
        panoramas: panoramasPayload
      }
      const urlEnd = '/v2/panoramas'
      const type = 'post'
      const resp = await api.asyncRequest(urlEnd, type, payload).catch(resp => {
      console.log('Before response')
      return resp
    })
  }

  // payload = [{"objectId":"2cd2244c-31bf-424b-831e-35360f422363","index":1},{"objectId":"012fd0f8-1bc9-4336-81fc-afd46836b0c9","index":2}]
  this.createPanoramas(payload).then(resp => {
    console.log('After then') 
  })

The console log 'Before resp' will trigger after 'After then'.

Why is this? And how to modify the async function so 'Before resp' triggers BEFORE 'After then'?

alex
  • 7,111
  • 15
  • 50
  • 77
  • `return splitNewPanoramas.forEach` returns undefined without waiting for the asynchronous code inside to execute - having a return inside a forEach suggests you don't know what forEach is used for ... also, your code seems to be missing some `}` and `)` to be valid – Jaromanda X Dec 28 '17 at 07:12
  • @JaromandaX there is no return in the forEach executor. The return is in the catch handler. – Kaiido Dec 28 '17 at 07:16
  • @Kaiido - true, that's what you get for relying on randomly indented code! I got fooled :p – Jaromanda X Dec 28 '17 at 07:18
  • @HMR uh I have to admit I don't quite understand your comment, so it will be hard for me to give you a concrete answer. Where in the question or in the dupe is there any mention of "*limiting the amount of requests made when mapping values to promises and passing it to Promise.all*" whatever that means? The question is *why the console logs main async's `then` before inner ones*. The answer is *because `forEach(async fn)` won't await*. And the workaround is *"Use `for ... of ...`*. – Kaiido Dec 28 '17 at 08:49
  • @Kaiido You are correct, I thought the `MAX_ARRAY_EACH_API_CALL` was there to limit the amount of requests but it limits the amount of data sent per request. – HMR Dec 28 '17 at 09:25

1 Answers1

0

You need to adjust your code because is not valid, but apart from that you need to return an array of promises and then wait for all of them to complete.

const api = {
  asyncRequest() {
    return new Promise(resolve => setTimeout(() => {
      resolve();
    }, 500));
  },
};

async function createPanoramas(
  { dispatch, commit, rootState },
  newPanoramas = {}
) {
  const splitNewPanoramas = [{}, {}, {}];

  return splitNewPanoramas.map(async panoramasPayload => {
    const payload = {
      buildingId: newPanoramas.buildingId,
      panoramas: panoramasPayload
    };
    const urlEnd = "/v2/panoramas";
    const type = "post";
    const resp = await api.asyncRequest(urlEnd, type, payload).then(resp => {
      console.log("Before response");
    });
    return resp;
  });
}

payload = [
  { objectId: "2cd2244c-31bf-424b-831e-35360f422363", index: 1 },
  { objectId: "012fd0f8-1bc9-4336-81fc-afd46836b0c9", index: 2 }
];

const responses = createPanoramas(payload).then(responses => {
  Promise.all(responses).then(resp => {
    console.log("After then");
  }).catch(err => { console.log(err); });
});
  • Here all the requests will be made in parallel. Not sure OP wants this. – Kaiido Dec 28 '17 at 08:07
  • Well, in that case he should replace `Promise.all` with a chain of promises (or `await` for each one of them) but the concept stays the same. You need to wait for all of them to complete before logging `After then` – Giacomo Cosimato Dec 28 '17 at 08:09
  • The function `splitNewPanoramas` returns `splitNewPanoramas.map`, this is an array and does not have a `then` function so `createPanoramas(payload).then(` will result in `then is not a function` error. Instead of `map(async ...` you can just do `map(fn`, the function will return a promise with `return api.asyncRequest` And because you log in the `then` it eventually returns to undefined. – HMR Dec 28 '17 at 08:22
  • 1
    Actually the code works. It's `createPanoramas.then`, not `splitNewPanoramas.then`. `createPanoramas` is an async function, which return an array of promises. You first wait for `createPanoramas`, then you wait for each one of the promises in the returned array, and then you log `After then` – Giacomo Cosimato Dec 28 '17 at 08:56