按顺序调用JavaScript代码的另一种方法是在两者之间拖延

我有这个代码最初在Python中。

SendSerialPortCommand("XXX") time.delay(0.5) SendSerialPortCommand("YYY") 

我把这个代码转换为node.js,但代码看起来更丑。

 SendSerialPortCommand("XXX"); setTimeout(function () { SendSerialPortCommand("YYY"); }, 500); 

想象一下,如果我的Python代码看起来像这样。

 SendSerialPortCommand("XXX") time.delay(0.5) SendSerialPortCommand("YYY") time.delay(0.5) SendSerialPortCommand("AAA") time.delay(0.5) SendSerialPortCommand("BBB") 

使用setTimeout()内的setTimeout() ,node.js代码看上去真的很难看。

怎样才能改善node.js代码的可读性? 我不在乎这个问题违反JavaScript的asynchronous性质。 重要的是可读性。

1.单线解决scheme:

以前接受的解决scheme只是使事情复杂化,并没有带来任何可读性或改进。 像这样做,只有一行

 setTimeout(function(){ SendSerialPortCommand("XXX"); }, 500); setTimeout(function(){ SendSerialPortCommand("YYY"); }, 1500); setTimeout(function(){ SendSerialPortCommand("ZZZ"); }, 2000); 

2.简单的可configuration解决scheme:

如果要使其可configuration ,请将选项移至上面的configuration,然后在循环中调用

 var schedulerData = [ {delay: 500, params: "XXX"}, {delay: 1500, params: "YYY"}, {delay: 2000, params: "ZZZ"} ]; for (var i in schedulerData) { var doTimeout = function(param, delay) { setTimeout(function(){ SendSerialPortCommand(param); }, delay ); }; doTimeout(schedulerData[i].params, schedulerData[i].delay); } 

这里是JSFiddle ,玩。

3.使用节点模块node-fibers

如果您想要通过node.js的高级解决scheme来“炫耀”,您可以采取node-fibers方式,并创build睡眠function,就像手册一样。

 var Fiber = require('fibers'); function sleep(ms) { var fiber = Fiber.current; setTimeout(function() { fiber.run(); }, ms); Fiber.yield(); } Fiber(function() { SendSerialPortCommand("XXX"); sleep(1000); SendSerialPortCommand("YYY"); }).run(); console.log('still executing the main thread'); 

node-fibers实现正在其他许多小型库中使用,就像WaitFor一样。 更多信息可以在这里find。

4.使用PromiseDeferred对象

您可以创build基于Promise的超时function。 乔描述了一个可能的实现。 但是我会提供一些小代码片断,以便更好地理解它是如何工作的,使用jQuery中的Defferred

 function wait(ms) { var deferred = $.Deferred(); setTimeout(deferred.resolve, ms); // We just need to return the promise not the whole deferred. return deferred.promise(); } // Use it wait(500).then(function () { SendSerialPortCommand("XXX"); }).wait(500).then(function () { SendSerialPortCommand("YYY"); }); 

如果不支持promise,则需要获取ECMAScript的polyfills ,例如core-js包中的PromisesPromises / A +实现的其他独立组件。

所得到的,也可以作为NPM的Deffered包得到,这个概念在这里很好的描述 。

你可以使用promise:

 function Delay(duration) { return new Promise((resolve) => { setTimeout(() => resolve(), duration); }); } function SendSerialPortCommand(command) { // Code that actually sends the command goes here... console.log(command); return Promise.resolve(); } Promise.resolve() .then(() => SendSerialPortCommand("XXX")) .then(() => Delay(500)) .then(() => SendSerialPortCommand("YYY")) .then(() => Delay(500)) .then(() => SendSerialPortCommand("AAA")) .then(() => Delay(500)) .then(() => SendSerialPortCommand("BBB")); 

或者,包括延迟到SendSerialPortCommand中:

 function SendSerialPortCommand(command, duration) { return new Promise((resolve) => { setTimeout(() => { // Code that actually sends the command goes here... resolve(); }, duration); }); } Promise.resolve() .then(() => SendSerialPortCommand("XXX", 500)) .then(() => SendSerialPortCommand("YYY", 500)) .then(() => SendSerialPortCommand("AAA", 500)) .then(() => SendSerialPortCommand("BBB", 500)); 

节点4+是使用箭头function所必需的,但如果需要的话,可以在没有它们的情况下轻松完成。

注意稍后执行function的时间。

 var scheduler = (function(){ var timer; function exec(call, delay){ //clearTimeout(timer); timer = setTimeout(call, delay); }; return exec; })() SendSerialPortCommand("XXX"); scheduler(function(){SendSerialPortCommand("YYY")}, 500); scheduler(function(){SendSerialPortCommand("AAA")}, 1000); scheduler(function(){SendSerialPortCommand("BBB")}, 1500); 

既然你问了其他的方法,我也会写一个。

 var commandIterator = 0; var portCommands = [ 'YYY', 'AAA' ]; SendSerialPortCommand(portCommands[commandIterator++]) var yourInterval = setInterval(function(){ SendSerialPortCommand(portCommands[commandIterator++]) }, 500); 

在任何时候你需要停止执行那些你只需要调用clearInterval(yourInterval)

如果你仍然关心可读性,你可以把迭代器放在setInterval中,并把内容包装在一个漂亮的函数中。 祝你好运!