与$ q同步使用forEach

时间:2016-03-31 15:43:37

标签: javascript arrays angularjs asynchronous

所以我有一种情况需要构建一个Object,然后将一些项注入到该Object中,然后进行API调用并将API的响应注入该Object。它是一个复杂的Object,所以我们只是假设没问题,但无论如何,我认为我需要同步执行这3个事情并使用array.forEach意味着它们是异步运行的。

我希望我的例子很容易理解,但基本上我做了三件事:

  • 创建一个空的类/课堂数组
  • 遍历一个Class ID数组,并为每个Class
  • 创建一个Object
  • 循环遍历Students数组并将其推入students对象
  • 内的Class数组
  • 循环遍历Options数组并将其推入options对象
  • 内的Class数组

最后,我对每个班级都有类似的东西:

{
  class_id: "abc123",
  students: [{}, {}, {}],
  options: [{}, {}, {}]
}

最后,这是我的代码:

// Create Array of Class Objects
var classes = [];

function processArray(array, func) {
  return $q(function(resolve, reject) {
    array.forEach(function(item, index) {
      func(item);
      if (index === (array.length - 1)) resolve();
    })
  })
}

// Create Courier Objects
processArray(classIds, function(id) {
  classes.push({class_id: id, students: [], options: []});
}).then(function(response) {
  // Inject Students into each Class
  processArray(students, function(students) {
    _.find(classes, {'class_id': student.class_id}).students.push(student);
  }).then(function(response) {
    // Inject classOptions into each Class
    processArray(classOptions, function(classOption) {
      _.find(classes, {'class_id': classOption.class_id}).classOptions.push(classOption);
    }).then(function(response) {
      // Print the classes
      console.log(classes);
    })
  })
});

我已经创建了一个同步执行的功能,但我想知道是否有人能想到更多,更清洁,更有效的方法来实现上述目标。它似乎非常hacky,如果我正确安排我的功能,也许我甚至不需要同步它。

2 个答案:

答案 0 :(得分:1)

您正在使用嵌套的承诺。这些很糟糕。承诺的一个主要优点是避免深度嵌套的“回调噩梦”。

使用此语法...

promise1.then(function(response1) {
  // do something with response 1 (and possibly create promise2 here based on response1 if required)
  return promise2
}).then(function(response2) {
  // do something with response 2
  return promise3
}).then(function(response3) {
  // do something with response 3
  // do something with promise 3???
}).catch(function(errorResponse) {
    // will trigger this on a failure in any of the above blocks
    // do something with error Response
});

答案 1 :(得分:1)

使用返回数组的基于Promise的API

processArray函数返回一个解析为null的promise。

//WRONG
//Returns a promise that resolves to null
//
function processArray(array, func) {
  return $q(function(resolve, reject) {
    array.forEach(function(item, index) {
      func(item);
      if (index === (array.length - 1)) resolve();
    })
  })
}

要返回解析为数组的承诺,请使用$q.all

//RIGHT
//Returns a promise that resolves to an array
//
function processArray(array, func) {
    var promiseArray = [];
    array.forEach(function(item, index) {
        promiseArray.push($q.when(func(item));
    });
    return $q.all(promiseArray);
}

无论是func(item)是返回值还是承诺,$q.when都会返回一个承诺。

请注意$q.all 不具弹性。它将通过一系列值解决,或者在第一个错误时解决被拒绝的问题。

processArray(array, func)
    .then( function onFulfilled(dataList) {
        //resolves with an array
        $scope.dataList = dataList;
    }).catch( function onRejected(firstError) {
        console.log(firstError);
    });

有关详细信息,请参阅AngularJS $q Service API Reference