ES5,如何在循环中使用promises

时间:2016-04-25 13:39:24

标签: node.js loops promise

说command_arr.length === 2

当我运行以下函数 device_execute_command 时。执行消息顺序是

finish one command
finish one command
has latest state?
has latest state?

我期待的是:

finish one command
has latest state?
finish one command
has latest state?

代码

var device_execute_command = function(command_arr) {
  // This is the main loop
  var i = 0;
  for(i=0; i < command_arr.length; i++) {
    var command = command_arr[i];
    var command_id = command.command_id;

    device_run_single_command(command).then(function(command){
      console.log();
      console.log("finish one command");
      console.log(command);

      return is_device_has_latest_state(command);
    }).then(function(command_with_condi){
      console.log();
      console.log("has latest state?");
      console.log(command_with_condi);

    });


  }

}

3 个答案:

答案 0 :(得分:1)

这是由于javascript的异步性质。你想要的是逐个执行承诺。而这不能通过简单地在循环迭代上调用promises来实现。实现这一目标的最简单方法可能是使用bluebird promise实现,它带有许多承诺执行流控制方法。

例如,您的案例中的顺序执行可以实现为:

const Promise = require('bluebird');

Promise.each(command_arr, function(command) {
  return device_run_single_command(command).then(function(command) {
    console.log();
    console.log("finish one command");
    console.log(command);    
    return is_device_has_latest_state(command);
  }).then(function(command_with_condi) {
    console.log();
    console.log("has latest state?");
    console.log(command_with_condi);    
  });
});

答案 1 :(得分:1)

如前所述,JavaScript承诺本质上是异步的。因此,在调用“device_run_single_command(command)”函数之后,for循环将移至下一次迭代。因此,观察到了输出。

在JavaScript中,这个问题可以通过各种机制解决。 Yerken和dfsq建议的方法肯定会奏效。随着async / await的未来到来,即使保留原始的for循环结构,也可以解决问题。现在,可以使用babel编译器来使用async / await。

async function device_execute_command(command_arr) {
  // This is the main loop
  var i = 0;
  for(i=0; i < command_arr.length; i++) {
    var command = command_arr[i];
    var command_id = command.command_id;

    command = await device_run_single_command(command);
    console.log();
    console.log("finish one command");
    console.log(command);

    var command_with_condi = await is_device_has_latest_state(command);
    console.log();
    console.log("has latest state?");
    console.log(command_with_condi);

  }

}

答案 2 :(得分:0)

问题在于Promise是异步的,并且简单的for循环不会暂停下一次迭代,以便等到上一次完成。

相反,您应该重新设计循环逻辑,并且只在前一次完成后运行下一次迭代。例如,使用IIFE,您可以这样做:

var device_execute_command = function(command_arr) {

  var i = 0;

  (function next() {
    command_arr[i] && device_run_single_command(command_arr[i++]).then(function(command) {
        console.log();
        console.log("finish one command");
        console.log(command);
        return is_device_has_latest_state(command);
      })
      .then(function(command_with_condi) {
        console.log();
        console.log("has latest state?");
        console.log(command_with_condi);
      })
      .then(next);
  })();

}