Home > Net >  How to know when the map function ends?
How to know when the map function ends?

Time:07-17

I have a "answersRequest" function, gets the id of the answers it writes to the "b" list

    const answersRequest = () => {
        let b = [];
        answers.map(answer => {
            axios({
                method: 'POST',
                url: 'http://127.0.0.1:8000/api/answers/',
                data: answer
            }).then(resp => {
                b.push(resp.data.id)
            })
        })
    }

And on completion of the map function, the below function needs to be run

const a = () => {setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: b}]); setAnswers([])};

but I don't know how to find out when the map function ends

help me please

CodePudding user response:

You basically need to push the return values from the axios call to an array and then use Promise.allSettled() or Promise.all() to wait for all the responses before you can continue processing that data.

// Just faking an axios call for this example:
function mockedAxios({ data }) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        data: {
          id: Math.random().toString(36).substr(2, 9),
          result: data * 2,
        },
      });
    }, 1000   Math.random() * 2000)
  });
}

async function answersRequest(answers) {  
  const promises = answers.map((answer) => {
    // Return each promise here:
    return mockedAxios({
      method: 'POST',
      url: 'http://127.0.0.1:8000/api/answers/',
      data: answer
    });
    // No need for a then block here, you can do it below in the `allSettled`'s `then`:
    // .then((resp) => {
    //   return resp.data.id;
    // });
  });
  
  // Wait for all responses and process the data:
  const IDs = await Promise.allSettled(promises).then((result) => {
    // result looks like { status: "fulfilled", value: { data: { id, result } } }
    return result.map(r => r.value.data.id);
  });

  return IDs;
}

async function update() {
  // You can now call and await this function from any other async function:
  const IDs = await answersRequest([1,2,3,4,5]);
  
  console.log(IDs);
  
  // And then, one you get the result, do whatever you need to do with it:
  // const a = () => {
  //   setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: IDs }]);
  //   setAnswers([]);
  // };
}

update();

CodePudding user response:

You can use Promise.all to resolve all promises at once.

const answersRequest = () => Promise.all(
  answers.map(answer => 
    axios({
      method: 'POST',
      url: 'http://127.0.0.1:8000/api/answers/',
      data: answer
    })
  )
);

Promise.all takes all the Promises passed to it (in this case, they are the HTTP requests) and only resolves when all the Promises are resolved. So, it's sending all the HTTP requests and waiting for all of them to finish. After that, the value of the returned Promise is an array containing all the responses, which means you don't need a separate variable for b anymore.

Then you can use Promise.then to call the second function.

answersRequest().then(values => {
  setQuestionsBlok(
    [...questionsBlok,
      {
        ...questionBlokInputs,
        answers: values.map(response => response.data.id)
      }
    ]
  );
  setAnswers([]);
});

Here, values is an array containing all the responses from the requests. Then, the map call extracts all the id's from the response.

CodePudding user response:

At first you should enable asynchronous to your requests.

After that you can call the function at the end of the loop like this:

const answersRequest = () => {
    let i = 0; // Loop counter
    let b = [];

    // It's called at the end of requests
    const funcA = (b) => {
        setQuestionsBlok([
            ...questionsBlok,
            {...questionBlokInputs, answers: b}
        ])
        setAnswers([])
    }

    // Post answers request function
    const createAnswers = async (answer) => {
        return await axios({
            method: 'POST',
            url: 'http://127.0.0.1:8000/api/answers/',
            data: answer
        })
    }

    answers.map(answer => {
        i  ; // Increase loop counter value
        createAnswers(answer).then(resp => {
            b.push(resp.data.id)

            // Runs specified function at the end of requests
            if(i === answers.length) {
                funcA(b)
            }
        })
    })
}

CodePudding user response:

You can use async/await to prompt your function to pause execution until a step completes:

const answersRequest = async () => {
    let b = [];
    await answers.map(answer => {
        axios({
            method: 'POST',
            url: 'http://127.0.0.1:8000/api/answers/',
            data: answer
        }).then(resp => {
            b.push(resp.data.id)
        })
    })
    // execution pauses here
    setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: b}]); setAnswers([])
}

In this manner, b will be defined as desired for the setQuestionsBlok call.

  • Related