Javascript Run asynchronous code for each element of the loop using Promises

I have a function that receives the object passed to it, with a key and data that are an array. I have to call the API to get additional information, which in turn is added back to the object and the whole object is returned.

My first approach was wrong because I was trying to pass data from .then() , but that was the wrong practice.

 function asignChecklistItems(taskArray) { // get all the people tasks passed in return new Promise(function(resolve, reject) { var promises = [] // Task Array: {"Person":[tasks,tasks,tasks]} for (var person in taskArray) { var individualTaskPerson = taskArray[person] // get the person tasks for (var individualTask in individualTaskPerson) { // here we get each individual task var task = individualTaskPerson[individualTask] // Check if the checklist is present, the .exists is a bool if (task.checklist.exists === true) { //Here we push the promise back into the promise array // retrieve is the async function promises.push( retrieveCheckListItems(task.checklist.checklistID) .then(checklistItems => { var complete = [] var incomplete = [] const items = checklistItems["checkItems"]; for (var each in items) { const item = items[each] if (item["state"] === "complete") { complete.push(item["name"]) } else { incomplete.push(item["name"]) } } task.checklist.completeItems.push(complete) task.checklist.incompleteItems.push(incomplete) return taskArray // used to be: resolve(taskArray) See **EDIT** }) .catch(err => { logError(err) reject(err) }) ) } else { // There no checklist } } } Promise.all(promises).then(function(x){ // Here when checked, all the items are pushed to the last person inside the array. // Eg. {PersonA:[tasks],PersonB:[tasks],PersonC:[tasks]} // All of the complete and incomplete items are added to Person C for some reason resolve(taskArray) }) }) } 

I tried many approaches, returning the whole promise, trying to return from the promise (which did not work because it was not allowed), and tried to run asynchronous code earlier, and moving the for loops into the promise. None of them worked, this is the closest one where it returns it for PersonC.

This was mainly related to other SO issues, such as which show how to use Promise.All .

Is this a preoper way to call a promise (asynchronous function) for each element of a for loop?

EDIT

Another error that was in the code is that if there is a promise that promises, for example, retrieveCheckListItems inside asignCheckListItems , it should not resolve , but should return Value. I updated the code to reflect this based on the production production code.

Apparently another problem was

+5
source share
1 answer

task.checklist.completeItems.push(complete) is executed in retrieveCheckListItems .then , which means the code is asynchronous.

At the same time, var task instead assigned in the for...in loop, which means that by the time .then run, the for...in iteration will be completed and the task will be the last assigned object.

Note that var variables have a function scope, which basically means that your code is equivalent:

 function asignChecklistItems(taskArray) { // get all the people tasks passed in return new Promise(function(resolve, reject) { var promises = [] var individualTaskPerson; var task; ... 

Fix it:

  • Or changing var task to let task (if you are using ES6). Then a variable is created in each for loop, and not inside the closing function.

    or

  • Replacing

     for (var individualTask in individualTaskPerson) { // here we get each individual task var task = individualTaskPerson[individualTask] 

    with

     Object.keys(individualTaskPerson).forEach(function(individualTask) { var task = individualTaskPerson[individualTask]; ... }); 

Do the same for the other for ... in loops and variables.

+2
source

Source: https://habr.com/ru/post/1273429/


All Articles