【问题标题】:Alternative ways of calling javascript code sequentially with delays in between顺序调用javascript代码的替代方法,中间有延迟
【发布时间】:2016-07-14 13:02:57
【问题描述】:

我在 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 的异步性质。重要的是可读性。

【问题讨论】:

  • 嵌套超时是异步'pyramid of doom' 的变体。另一种方法是使用某种形式的流:这包括 Promise。

标签: javascript node.js settimeout timedelay


【解决方案1】:

注意稍后运行函数的时间安排。

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

【讨论】:

  • 由于所有的定时器都是同时启动的,所以与原来的相比,这会“漂移”,特别是如果被调用的函数需要相关的时间。
  • 如果其中一个函数的执行时间超过了您指定的延迟差异怎么办?我想将其与承诺相结合是正确的做法
  • 奇怪的解决方案,为什么它比单线更丑?!没有得到这个。制作them configurable, or do one-liners with Timers,不要过于复杂。
【解决方案2】:

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

var commandIterator = 0;
var portCommands = [
   'YYY',
   'AAA'
];
SendSerialPortCommand(portCommands[commandIterator++])

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

在任何时候你都需要停止执行你刚刚调用的那些命令 clearInterval(yourInterval)

如果您仍然关心可读性,您可以将迭代器包含在 setInterval 中,并将内容包装在一个干净的函数中。祝你好运!

【讨论】:

    【解决方案3】:

    1。单线解决方案:

    Previously accepted solution 只是使事情复杂化,并没有带来任何可读性或改进。那么就这样做吧,单行

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

    2。简单的可配置解决方案:

    如果您想使其可配置,请将选项移至上述配置,然后在循环中调用,类似:

    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 来“炫耀”高级解决方案,你可以去 node-fibers 的方式,并创建 sleep 功能,就像他们的手册.

    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。更多信息可以在here找到。

    4。使用Promise & Deferred 对象

    您可以创建一个基于 Promise 的超时函数。 Joe 描述了一种可能的实现方式。但我会提供小代码 sn-p,以便更容易理解它的实际工作原理,使用来自 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,例如 Promises from core-js packagePromises/A+ 实现的任何其他独立组件.

    延迟,也可以作为单独的Deffered package for NPM 获得,concept is nicely described here

    【讨论】:

      【解决方案4】:

      你可以使用承诺:

      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+,但如果需要,可以在没有它们的情况下轻松完成。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多