在node.js中编写非冒号函数的正确方法

nos*_*bor 0 javascript node.js promise

我写了一个返回Promise的简单函数,所以应该是非阻塞的(在我看来).不幸的是,程序似乎停止等待Promise完成.我不确定这里有什么不对.

function longRunningFunc(val, mod) {
    return new Promise((resolve, reject) => {
        sum = 0;
        for (var i = 0; i < 100000; i++) {
            for (var j = 0; j < val; j++) {
                sum += i + j % mod
            }
        }
        resolve(sum)
    })
}

console.log("before")
longRunningFunc(1000, 3).then((res) => {
    console.log("Result: " + res)
})
console.log("after")
Run Code Online (Sandbox Code Playgroud)

输出看起来像预期的:

before     // delay before printing below lines
after
Result: 5000049900000
Run Code Online (Sandbox Code Playgroud)

但程序在打印第二行和第三行之前等待.你能解释一下,首先打印"之前"和"之后",然后(经过一段时间)结果的正确方法是什么?

jfr*_*d00 6

在承诺中包装代码(就像你已经完成的那样)并不会使它成为非阻塞代码.Promise执行程序函数(您传递给的回调new Promise(fn)被同步调用并将阻止,这就是您看到输出延迟的原因.

实际上,没有办法创建自己的普通Javascript代码(就像你拥有的那样),除非将它放入子进程,使用一些第三方库创建Javascript的新线程或使用新的实验节点线程的.js API.常规node.js将您的Javascript作为阻塞和单线程运行,无论它是否包含在承诺中.

您可以使用诸如setTimeout()更改"何时"运行代码的内容,但无论何时运行,它仍然会阻塞(一旦它开始执行,其他任何东西都可以运行,直到它完成).node.js库中的异步操作都使用某种形式的底层本机代码,允许它们是异步的(或者它们只使用本身使用本机代码实现的其他node.js异步API).

但程序在打印第二行和第三行之前等待.你能解释一下,首先打印"之前"和"之后",然后(经过一段时间)结果的正确方法是什么?

如上所述,在promise执行函数中包装东西不会使它们异步.如果你想"转移"运行时间的时间(认为它们仍然是同步的),你可以使用a setTimeout(),但这并不是真正做任何非阻塞,它只是让它运行得更晚(运行时仍然阻塞).

所以,你可以这样做:

function longRunningFunc(val, mod) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            sum = 0;
            for (var i = 0; i < 100000; i++) {
                for (var j = 0; j < val; j++) {
                    sum += i + j % mod
                }
            }
            resolve(sum)
        }, 10);
    })
}
Run Code Online (Sandbox Code Playgroud)

这将重新安排耗时的for循环以便稍后运行并且可能"显示"为非阻塞,但它实际上仍然阻止 - 它只是稍后运行.要使其真正无阻塞,您必须使用前面提到的技术之一将其从主Javascript线程中删除.

在node.js中创建实际非阻塞代码的方法:

  1. 在单独的子进程中运行它,并在完成后获得异步通知.
  2. 在node.js v11中使用新的实验性工作线程
  3. 将您自己的本机代码插件编写到node.js,并在您的实现(或其他OS级别异步工具)中使用libuv线程或OS级别线程.
  4. 构建在以前存在的异步API之上,并且没有自己的代码在主线程中占用很长时间.

  • 对于 C++ 插件中的操作系统级线程,根据我的经验,[libuv](https://github.com/libuv/libuv) 非常好。这是[我找到的一个基本示例](https://gist.github.com/dmh2000/9519489)。我个人使用它进行实时图像处理以在非阻塞线程中进行对象检测,然后 Node.js 将检测到的质心分发到连接的 TCP 客户端(使用数据驱动电机向检测到的对象移动)。 (2认同)