【问题标题】:Is node.js setTimeout() working?node.js setTimeout() 工作吗?
【发布时间】:2015-11-01 20:38:41
【问题描述】:

我是 Node.js 的新手。我需要做些什么才能让 setTimeout() 工作吗?

这是一个代码 sn-p。

在完成时设置 appMsg.doneLoadTables = true 的异步代码

do {
  console.log('waiting ...   ' + appMsg.doneLoadTables);
  setTimeout(function() { console.log('waiting ...'); }, 1000);
} while (!appMsg.doneLoadTables);

症状:

  • (虽然对 console.log 的两次调用相似,但只有第一次会打印 appMsg.doneLoadTables 的值。)每个结果都包含该值。
  • console.log 调用之间的间隔远小于 1000 毫秒。 (我怀疑间距与计算机可以处理此处显示的循环一样快。)
  • 虽然我希望异步例程可以在我在这里打算的延迟期间继续处理,但我从未见过这个循环完成;就好像循环占用了所有处理资源并阻止异步例程完成其工作并设置将结束此循环的变量。

我对 Node 4.2.1 有过这种体验;安装 Node 5.0.0 后我继续拥有这种体验。

我已经看到关于 setTimeout() 的类似问题已经在这里被问过很多次了。我希望我在 setTimeout() 中使用 IIFE 可以使这个问题与所有这些问题不同。

提前感谢您提供的任何帮助...

【问题讨论】:

  • “我希望我在 setTimeout() 中使用 IIFE 可以使这个问题与所有这些问题不同。” — 它没有。
  • 您传递给 setTimeout 的匿名函数不是 IIFE,因为它不会立即被调用。
  • 我撤回了这个问题。感谢所有的答案。我更好地理解异步是如何工作的。如果我知道我在重复之前的问题,我就不会提交了。这是一个善良而熟练的团队!

标签: javascript node.js


【解决方案1】:

JavaScript 是单线程的。 setTimeout 不是 sleep 的一种形式,它会在该行暂停代码。它的工作原理是“调度”您的回调以供稍后使用,并在堆栈耗尽时执行它(引擎什么都不做)并且至少在 n 毫秒后执行,其中 n 是您放置的延迟(以毫秒为单位)。

现在您的代码无法运行,因为它永远不会退出循环。该代码没有机会执行其他代码(您希望运行并更改appMsg.doneLoadTables 值的代码)。它所做的一切都在记录“等待...... [某事]”。

基本上你是在投票。你可以改用setInterval。当appMsg.doneLoadTablestrue 时,使用clearInterval 停止轮询。

【讨论】:

  • 是的,setTimeout 是另一种选择。可用于一直调用直到满足条件,然后停止调用。
【解决方案2】:

我不是 100% 确定你的目标是什么......但是也许这个 sn-p 会带你去你想去的地方(我选择了 setTimeout 而不是 setInterval):

var appMsg = {doneLoadTables: false};

var stillLoading = function() {
    if(false === appMsg.doneLoadTables) {
        console.log('waiting ...   ' + appMsg.doneLoadTables);
        setTimeout(stillLoading, 50);
    }
    else {
        console.log('Loading complete.');
        process.exit();
    }
}

stillLoading();
setTimeout(function(){
    console.log('Setting appMsg.doneLoadTables = true');
    appMsg.doneLoadTables = true;
}, 1000);

脚本每 50 毫秒轮询一次状态,并在 1 秒后标记为“完成”。

输出如下所示

waiting ...   false
waiting ...   false
waiting ...   false
waiting ...   false
...
Setting appMsg.doneLoadTables = true
Loading complete.

【讨论】:

    【解决方案3】:

    (虽然对 console.log 的两次调用相似,但只有第一次会打印 appMsg.doneLoadTables 的值。)每个结果都包含该值。

    这是正确的行为,因为您永远不会退出 while 循环。您将停留在永远循环的同一个事件框架中。

    对 console.log 的调用间隔远小于 1000 毫秒。 (我怀疑间距与计算机可以处理此处显示的循环一样快。)

    这又是正确的行为,因为您传递给 setTimeout 的回调永远不会执行,除非您退出 do-while 循环,而您永远不会这样做。因此,您只需继续调用第一个 console.log 语句,然后将回调添加到事件循环以在 1000 毫秒内执行,而不会给它(您传递的回调)执行的机会。

    虽然我希望异步例程可以在我打算在这里的延迟期间继续处理,但我从未见过这个循环完成;就好像循环占用了所有处理资源并阻止异步例程完成它们的工作并阻止设置将结束此循环的变量。

    循环永远不会结束,因为它没有实现完成它的逻辑。 “异步例程”无法继续,因为这将需要退出当前事件框架(运行无限循环)并启动下一个具有您传递给 setTimeout 的回调的事件框架。

    希望我的解释能帮助您了解异步 JavaScript 的工作原理。

    【讨论】:

      猜你喜欢
      • 2011-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多