Javascript为承诺循环的每个项目运行异步代码

时间:2017-11-16 10:41:07

标签: javascript node.js asynchronous promise es6-promise

我有一个函数,它将一个对象传递给它,其中键和数据是一个数组。 我必须调用API来获取附加信息,然后将其添加回对象并返回整个对象。

我的第一种方法不正确,因为我试图将数据传递出.then(),但这是错误的做法。

function asignChecklistItems(taskArray) { 
    // get all the people's 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's 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's 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)

        })

        })
    }

我已经尝试了很多方法,返回整个承诺,尝试从promise中返回(由于不允许这样做不起作用),并尝试更早地运行异步代码,并将for循环移动到诺言。他们都没有工作,这是最接近的,它为PersonC返回它。

这主要基于其他SO问题,例如one,其中展示了如何使用Promise.All

这是为for循环的每个元素调用promise(异步函数)的preoper方法吗?

修改

代码中的另一个错误是,如果有承诺提交承诺,例如retrieveCheckListItems内的asignCheckListItems,则不应resolve本身,但它应该return价值。我根据工作生产代码更新了代码以反映这一点。

显然我是另一个问题

1 个答案:

答案 0 :(得分:2)

您正在task.checklist.completeItems.push(complete) retrieveCheckListItems中执行.then,这意味着代码是异步的。

同时,在var task循环中分配for...in,这意味着在您的.then被触发时,for...in次迭代将是完成,task将是最后分配的对象。

请注意,var变量具有函数范围,这基本上意味着您的代码等同于:

function asignChecklistItems(taskArray) { 
    // get all the people's tasks passed in
    return new Promise(function(resolve, reject) {

        var promises = []
        var individualTaskPerson;
        var task;

        ...

修复:

  1. var task更改为let task(如果您使用的是ES6)。然后,这将在每个for循环中创建变量,而不是在封闭函数内。

  2. 替换

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

    Object.keys(individualTaskPerson).forEach(function(individualTask) {
        var task = individualTaskPerson[individualTask];  
    
         ...
    });
    
  3. 对于另一个在循环和变量中执行相同操作。