2016-04-25 24 views
1

说command_arr.length === 2ES5,如何在一个循环中使用的承诺

当我运行下面的函数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

的问题是,承诺是异步的,简单的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); 
    })(); 

} 
1

这是因为JavaScript的异步特性。你想要的是一个接一个地执行承诺。这不能通过简单地在循环迭代中调用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

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

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

    } 

}