【问题标题】:Node.js endless loop function, quit upon certain user inputNode.js 无限循环功能,在某些用户输入时退出
【发布时间】:2014-08-02 15:25:03
【问题描述】:

我不太了解节点在异步和循环方面的工作原理。 我想在这里实现的是让控制台打印出“Command:”并等待用户输入。但是在它等待时,我希望它无休止地运行“someRandomFunction()”,直到用户在终端上输入“exit”。

感谢所有帮助 - 可能还有解释,以便我能理解!

谢谢! :)

var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.question("Command: ", function(answer) {
    if (answer == "exit"){
        rl.close();
    } else {
        // If not "exit", How do I recall the function again?
    }
});

someRandomFunction();

【问题讨论】:

  • Node.js 不会并行执行脚本。如果你真的有无限循环,它会阻止你正在等待用户输入的回调。那么你想在你的someRandomFunction 中做什么呢?
  • 为什么不使用 setInterval()someRandomFunction() ?关键是要使someRandomFunction() 不会花费很长时间,并将其步骤累积到闭包或全局。当它运行时,什么都不会。
  • @t.niese 我遇到了这个问题,今天早上(在阅读您的帖子之前)我才弄清楚为什么它不允许我输入终端。感谢您的来信!
  • @Paul 我考虑过 setInterval 但对运行 someRandomFunction 有不同的用途 - 最终使用 cron 因为它符合我的需要。感谢您的洞察力!

标签: javascript node.js


【解决方案1】:

我建议像这样使函数可重复。

var rl = readline.createInterface({
 input: process.stdin,
 output: process.stdout
});

var waitForUserInput = function() {
  rl.question("Command: ", function(answer) {
    if (answer == "exit"){
        rl.close();
    } else {
        waitForUserInput();
    }
  });
}

然后调用

waitForUserInput();
someRandomFunction();

我不确定您用于 .question 的语法是否正确,这部分代码是否有效?

你也可以这样写。

var rl = readline.createInterface({
 input: process.stdin,
 output: process.stdout
});

function waitForUserInput() {
  rl.question("Command: ", function(answer) {
    if (answer == "exit"){
        rl.close();
    } else {
        waitForUserInput();
    }
  });
}

这里的重要教训是,要重用一个函数,它必须被命名并在范围内可用。如果您对此还有任何疑问,请提出。

【讨论】:

  • 现在一切正常!谢谢! .question 有效,我从readline获得了它的功能@
  • 酷我猜它是我不知道的一些库。 :D 希望你现在可以继续你的项目!
  • 我还差一个解锁点赞,等我解锁就好了!
  • 请原谅这个菜鸟问题,但这不是通过不断调用自身来不断添加到堆栈中吗?
  • 您可以使用简单的 html 和 js 文件对其进行测试,运行它并使用 chrome source > callstack 进行检查,请参考这篇文章进行测试:stackoverflow.com/questions/10761894/…。每次我们回调同一个函数时,它都会向调用堆栈添加新条目。
【解决方案2】:

另一个答案很好,但不必要地使用了递归。

解决这个问题的关键是在您的脑海中将其他语言中使用的基于循环的简单方法与 Node 的异步方法分开。

在其他语言中,您可能会使用这样的循环:

while not finished:
  line = readline.read() 
  if line == 'woof':
    print('BARK')
  elif line == 'exit':
    finished = True
  ... # etc

Node,至少对于 Readline,不能以这种方式工作。

在 Node 中,您启动 Readline,为其提供事件处理程序,然后返回,然后处理 readline 循环的完成稍后

考虑一下这段代码,你可以复制粘贴运行:

const readline = require('readline');

function replDemo() {
  return new Promise(function(resolve, reject) {
    let rl = readline.createInterface(process.stdin, process.stdout)
    rl.setPrompt('ready> ')
    rl.prompt();
    rl.on('line', function(line) {
      if (line === "exit" || line === "quit" || line == 'q') {
        rl.close()
        return // bail here, so rl.prompt() isn't called again
      }

      if (line === "help" || line === '?') {
        console.log(`commands:\n  woof\n  exit|quit\n`)
      } else if (line === "woof") {
        console.log('BARK!')
      } else if (line === "hello") {
        console.log('Hi there')
      } else {
        console.log(`unknown command: "${line}"`)
      }
      rl.prompt()

    }).on('close',function(){
      console.log('bye')
      resolve(42) // this is the final result of the function
    });
  })
}

async function run() {
  try {
    let replResult = await replDemo()
    console.log('repl result:', replResult)

  } catch(e) {
    console.log('failed:', e)
  }
}

run()

运行这个,你会得到这样的输出:

$ node src/repl-demo.js
ready> hello
Hi there
ready> boo
unknown command: "boo"
ready> woof
BARK!
ready> exit
bye
repl result: 42

注意run 函数调用replDemo 并“等待”承诺的结果。

如果你对 async/await 不熟悉,下面是同样的逻辑,写成“传统”的 Promise 风格:

function run2() {
  replDemo().then(result => {
    console.log('repl result:', result)
  }).catch(e => {
    console.log('failed:', e)
  })
  console.log('replDemo has been called')
}

请注意,我添加输出“replDemo 已被调用”是有原因的 - 运行上面的代码会显示如下输出:

$ node src/repl-demo.js
ready> replDemo has been called
woof
BARK!
ready> hello
Hi there
ready> bye
repl result: 42

注意“replDemo 已被调用”是如何在第一个“ready>”提示之后立即出现的。那是因为replDemo() 函数立即返回,然后run2() 立即退出,而main 全部完成——但readline 仍在执行!

如果您像我这样具有命令式编程背景,这很难掌握。 nodejs核心的异步事件驱动循环一直运行,直到所有工作完成,这发生在最后一个promise被解决时,这发生在readline实例“关闭”时,当输入“exit”时发生用户(或收到 EOF,在大多数系统上是 CTRL+D,在 Windows 上是 CTRL+Z)。

【讨论】:

  • 完全正确。我会编辑...
猜你喜欢
  • 2012-01-24
  • 2014-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-17
  • 2016-11-07
  • 1970-01-01
相关资源
最近更新 更多