2016-04-25 23 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); 

    } 

}