一对多的承诺

时间:2014-06-16 03:43:58

标签: javascript promise

我有一个客户列表,然后每个客户都有一系列要运行的任务。在psudeocode中:

Get all customers
For each customer, get list of tasks
For each task, run task

但是,我希望在运行这些任务时利用JavaScript的异步特性。有了承诺,我可以做类似的事情:

getAllCustomers().then(function(customers) {
  var taskGetters = [];
  customers.forEach(function(customer) {
    taskGetters.push(getCustomerTasks(customer).then(function(tasks) {
      var taskDoers = [];

      tasks.forEach(function(task) {
        taskDoers.push(doTask());
      });

      return promise.all(taskDoers);
    });
  });

  return promise.all(taskGetters);
}).then(function() {
  // clean up
}).catch(function() {
  // handle error
});

然而,这遇到了回调所带来的一些结构性问题 - 我开始嵌套事物而不是保持应有的清晰的psudeo同步结构。如何在保留承诺的结构优势的同时解决这个问题?

3 个答案:

答案 0 :(得分:2)

如果我记得你正在使用蓝鸟,那么你可以:

getAllCustomers().map(function(customer) {
  return Promise.map(customer, getCustomerTasks).map(doTask);
}).then(function() {

}).catch(function() {
  // handle error
});

答案 1 :(得分:1)

  

然而,这遇到了回调所带来的一些结构性问题 - 我开始嵌套事物而不是保持应有的清晰的psudeo同步结构。

没有。甚至同步等价物也会嵌套:你在那里有两个循环:

customers = getAllCustomers()
for each customer in customers
  tasks = getTasklist()
  for each task in tasks
    run(task)

但是,对于更干净的代码,我建议使用map代替forEach进行手动数组构建:

getAllCustomers()
.then(function(customers) {
  return promise.all(customers.map(function(customer) {
    return getCustomerTasks(customer)
    .then(function(tasks) {
      return promise.all(tasks.map(doTask));
    });
  }));
}).then(function() {
  // clean up
}).catch(function() {
  // handle error
});

某些承诺库甚至可能为.then((X)=>all(X.map(…)))模式提供快捷方法。

答案 2 :(得分:0)

我认为你的每个回调都是一个函数,而不是一个闭包,你将有一个更好的结构:

function processTasks(tasks){
  var taskDoers = [];

  tasks.forEach(function(task) {
    taskDoers.push(doTask());
  });

  return promise.all(taskDoers);
}

function processCustomer(customer){
    taskGetters.push(getCustomerTasks(customer).then(processTasks));
}

function processCustomers(customers){
    customers.forEach(processCustomer);
}

function cleanup(){

}
function handle(error){

}
getAllCustomers().then(processCustomers).then(cleanup).catch(handle);

您可以根据需要将尽可能多的闭包分开。