说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);
});
}
}
答案 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);
})();
}