在下面的javascript程序中(欧拉问题5)我正在练习编写异步/非阻塞函数。该程序试图找到能被数字 1-10 整除的最小数字。 2520 是第一个最小的,这是程序应该停止的地方。
我设置了程序,以便如果函数一起运行,则应首先完成第二个 checkNum 并先打印第二个,然后打印第一个,但这种情况没有发生?
如何让函数同时运行,而不是一个接一个地运行?我期望我调用的第二个 checkNum 函数的回调首先被调用(因为它开始更接近答案),然后是第一个,但事实并非如此。非常感谢!
var divides = function(a, b) {
return b % a == 0;
};
function checkNum(counter, callback) {
var noRemainder = 0;
var forward = true;
while (forward)
{
for (var i = 1; i <= 10; i++) {
if (divides(i, counter))
{ noRemainder++; }
}
if (noRemainder == 10) {
console.log(counter);
forward = false;
callback(counter);
} else {
console.log(noRemainder);
noRemainder = 0;
counter++;
console.log(counter);
}
}
}
checkNum(1, function(counter) {
setTimeout(function(){
console.log("The counter is: " + counter)},3000)
}
);
checkNum(2500, function(counter) {
setTimeout(function(){
console.log("The counter2 is: " + counter) },3000)
}
);
最佳答案
因为 checkNum
是一个纯粹受 CPU 限制的函数 - 也就是说,它所做的唯一事情就是在紧密循环中执行计算 - 没有理由使其异步。根据定义,该功能是同步的;在计算完成之前,控制权不会返回给调用者。考虑以下异步样式:
checkNum(n, function(err, result) {
console.log(result);
});
console.log('Next line');
...和同步风格:
console.log( checkNum(n) );
console.log('Next line');
在这两种情况下,checkNum
的结果都将打印在“下一行”之前。即使在异步风格中,直到 checkNum
调用其回调并且回调完成之后才返回控制。 (将此与真正的异步函数进行比较,其中“下一行”将在回调获取结果之前打印。)
Node 的真正魔力来自于这样一个事实:大多数昂贵操作(例如 I/O)是由 native 代码在单独的线程上执行的,当它们完成时,它们会调用 JavaScript主线程回调。因此,执行 JavaScript 所花费的时间非常少,因此您的应用程序性能非常出色。
但是,如果您发现自己在 JavaScript 中编写了像这样昂贵的循环和计算,则必须记住,您将在函数运行的时间内阻塞一切。其他线程上发生的事情将排队,并且您的应用程序代码将没有机会执行任何操作,直到昂贵的函数返回。
有多种方法可以解决此限制(按性能顺序排列):
- 将计算分解为多个 block 并使用
nextTick
开始对每个 block 进行处理。这允许任何排队的事件在 block 之间进行处理。 - 将计算函数移至单独的文件中,并启动一个新进程来实际进行计算。这使得您的主应用程序在等待结果时可以正常运行。您需要使用
fork
因为它带有内置 IPC,所以可以做到这一点。 Here's an example fibonacci calculator.请记住,这确实会带来开销:启动新 Node 进程需要约 30 毫秒和至少 10 MB 的 RAM。 - Actually run your JavaScript code on a separate thread.请注意,代码将与应用程序的其余部分隔离运行;您的线程将无法访问主应用程序中的任何变量。这与进程 fork 方法非常相似,但速度更快,因为您避免了生成新进程的开销。
- 使用 native (C++) 代码进行计算,您可以在单独的线程上自由地进行计算。 Here's a native fibonacci example.
关于javascript - 如何使这个 Node.js 程序异步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19128286/