ES5,如何在循环中使用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); }); } } 

问题是Promise是asynchronous的,简单的for-loop不会暂停下一次迭代,以便等到上一次完成。

相反,你应该重新devise你的循环逻辑,并且只有在完成之前才运行下一次迭代。 例如,用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); })(); } 

这是由于JavaScript的asynchronous性质。 你想要的是一个一个的执行承诺。 这只能通过在循环迭代中调用promise来实现。 实现这个最简单的方法可能是通过使用bluebird承诺实现,它带有许多承诺执行stream控制的方法。

例如,在你的情况下顺序执行可以实现为:

 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); }); }); 

如前所述,JavaScript承诺本质上是asynchronous的。 所以,在调用“device_run_single_command(command)”函数之后,for循环会移动到下一次迭代。 因此,观察到的产出。

在JavaScript中,这个问题可以通过各种机制来解决。 Yerken和dfsq提出的方法肯定会起作用。 随着未来asynchronous/等待的到来,甚至可以通过保留原来的循环结构来解决问题。 目前,使用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); } }