【问题标题】:Chaining setTimeout Calls Recursively with Javascript Callbacks使用 Javascript 回调以递归方式链接 setTimeout 调用
【发布时间】:2022-11-22 19:03:28
【问题描述】:

我在 Javascript 中有一个简单的 setTimeout 函数,它只允许我指定延迟任何操作的时间量,然后只是一个用于链接的回调

function delay(item, callback) {
    return new Promise(function(response, reject) {
        setTimeout(function() {
            console.log(item.message);
            response(callback());
        }, item.time);
    });
}

我可以在嵌套回调中很好地使用它,但它开始变得非常乏味和丑陋,无法用于更长的链

function delayChain() {

    const items = [
        {message:"Waited 01 sec", time:1000},
        {message:"Waited 02 sec", time:2000},
        {message:"Waited 04 sec", time:4000},
        {message:"Waited 03 sec", time:3000}
    ];

    delay(items[0], function() {
        delay(items[1], function() {
            delay(items[2], function() {
                delay(items[3], function() {
                    console.log("Done Waiting");
                });
            });
        });
    });

}

我想知道是否有可能以递归的方式做类似的事情

更新

似乎可以通过像这样使用 async/await 来完成类似的事情而不需要回调

async function delayChainAsync() {

    const items = [
        {message:"Waited 01 sec", time:1000},
        {message:"Waited 02 sec", time:2000},
        {message:"Waited 04 sec", time:4000},
        {message:"Waited 03 sec", time:3000}
    ];

    for(let item of items) {
        await delay(item, function() {});
    }

    console.log("Done Waiting");

}

但我希望仍然像在原始延迟函数中那样使用回调链

【问题讨论】:

  • This answer 副本看起来像你想要的
  • 这个答案很接近,但它似乎没有使用回调,我只是更新我的问题以更加强调回调而不是异步/等待
  • 使用 Promise 可以吗?或者您只想要一个带有普通回调的解决方案?
  • Promise 主要只是为了确保出于测试目的而延迟回调,但回调是 mvp
  • 我重新打开这个问题,因为已经澄清它主要是关于回调而不是 promises/async/await(重复的答案指的是)

标签: javascript recursion promise callback settimeout


【解决方案1】:

一种方法是使用items 上的循环创建嵌套函数。这个想法是通过 items 向后循环,首先创建最内层的嵌套函数,并保留对它的引用,这样当您移动到数组中的下一项时,您可以创建使用前一个函数的下一个嵌套函数您创建为delay 的回调。循环完成后,您可以调用您创建的最终函数来启动最外层函数以开始回调链:

function delay(item, callback) {
  setTimeout(function() {
    console.log(item.message);
    callback();
  }, item.time);
}

function delayChain() {
  const items = [ {message:"Waited 01 sec", time:1000}, {message:"Waited 02 sec", time:2000}, {message:"Waited 04 sec", time:4000}, {message:"Waited 03 sec", time:3000} ];
  
  let nextFn = () => console.log("Done waiting"); // the most inner nested function
  for(let i = items.length - 1; i >= 0; i--) {
    const ref = nextFn; // required so that the closure below refers to this current function and doesn't change
    nextFn = function() {
      delay(items[i], ref);
    };
  }
  nextFn();
}

delayChain();

另一种选择是通过将计数器传递给delayChain来递归地(伪)执行此操作,以确定我们需要为每个对delayChain的新调用创建delay的对象:

function delay(item, callback) {
  setTimeout(function() {
    console.log(item.message);
    callback();
  }, item.time);
}

function delayChain(i = 0) {
  const items = [ {message:"Waited 01 sec", time:1000}, {message:"Waited 02 sec", time:2000}, {message:"Waited 04 sec", time:4000}, {message:"Waited 03 sec", time:3000} ];

  if(i === items.length)
    console.log("Done waiting"); // the most inner nested function
  else
    delay(items[i], () => delayChain(++i));
}

delayChain();

另外请注意,您的 delay 函数不需要返回 Promise。当您尝试使用回调时,它不需要返回 Promise,因为从未使用过 Promise 值。大多数时候,您的函数应该接受回调作为参数或者返回一个承诺,但不能同时返回。

【讨论】:

    猜你喜欢
    • 2018-04-09
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 2016-03-03
    • 2015-11-02
    • 2020-11-18
    • 2019-11-19
    • 2019-06-10
    相关资源
    最近更新 更多