Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/432.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在Node.js中编写非阻塞函数的正确方法_Javascript_Node.js_Promise - Fatal编程技术网

Javascript 在Node.js中编写非阻塞函数的正确方法

Javascript 在Node.js中编写非阻塞函数的正确方法,javascript,node.js,promise,Javascript,Node.js,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 &l

我写了一个简单的函数,返回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")

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

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

事实上,没有办法创建自己的纯Javascript代码(就像您所拥有的那样)这是无阻塞的,除了将其放入子进程、使用WorkerThread、使用创建新Javascript线程的第三方库或使用新的实验node.js API进行线程外。常规node.js以阻塞和单线程的方式运行Javascript,无论它是否包装在承诺中

您可以使用
setTimeout()
之类的方法来更改代码运行的“时间”,但每当代码运行时,它仍然会阻塞(一旦开始执行,在完成之前,其他任何操作都无法运行)。node.js库中的异步操作都使用某种形式的底层本机代码,允许它们异步(或者他们只使用其他node.js异步API,这些API本身使用本机代码实现)

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

正如我上面所说的,在promise executor函数中封装东西并不会使它们异步。如果你想“改变”事情运行的时间(虽然它们仍然是同步的),你可以使用
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);
    })
}
函数longRunningFunc(val,mod){
返回新承诺((解决、拒绝)=>{
设置超时(()=>{
总和=0;
对于(变量i=0;i<100000;i++){
对于(var j=0;j
这将重新安排耗时的
循环,使其在以后运行,并且可能“看起来”是非阻塞的,但实际上它仍然会阻塞—它只是在以后运行。要使其真正非阻塞,您必须使用前面提到的技术之一将其从主Javascript线程中释放出来

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

  • 在单独的子进程中运行它,并在完成时获得异步通知
  • 在node.js v11中使用新的实验
  • 在node.js中编写自己的本机代码插件,并在实现中使用libuv线程或操作系统级线程(或其他操作系统级异步工具)
  • 构建在以前存在的异步API之上,并且没有在主线程中花费很长时间的代码

  • promise的executor函数是同步运行的,这就是代码阻塞执行主线程的原因

    为了不阻塞执行的主线程,您需要在执行长时间运行的任务时周期性地、协同地产生控制。实际上,您需要将任务拆分为子任务,然后在事件循环的新标记上协调子任务的运行。这样,您就可以为其他任务分配控制权(如呈现和响应用户输入)运行的机会

    您可以使用promise API编写自己的异步循环,也可以使用异步函数。异步函数支持函数的挂起和重新生成(可重入),并隐藏大部分复杂性

    下面的代码使用
    setTimeout
    将子任务移动到新的事件循环标记上。当然,这可以推广,批处理可以用于在任务进度和UI响应性之间找到平衡;此解决方案中的批处理大小仅为1,因此进度缓慢

    最后:这类问题的真正解决方案可能是一个解决方案

    const$=document.querySelector.bind(文档)
    常量大号=1000
    让计数=0
    //请注意,这也可以使用requestIdleCallback或requestAnimationFrame
    const tick=(fn)=>新承诺((解析)=>设置超时(()=>解析(fn),5))
    异步函数longRunningTask(){
    而(count++console.log(`***已完成***`))
    $('button')。onclick=()=>$('#output')。innerHTML+=`当前计数为:${count}
    `
    *{
    字号:16pt;
    颜色:灰色;
    填充:15px;
    }
    单击我以查看UI是否仍有响应。
    
    好吧,如果你想在“一段时间后”真正测试,你可以在你的解析(sum)周围加上一个setTimeout声明。这是行不通的。你只为你的代码得到一个线程。在承诺或超时中打包同步代码不会改变。如果你想编写异步代码,你需要创建一个相关的:对于客户端,也有用于创建单独线程任务的。对于C++插件中的OS级线程来说,已经相当不错了。根据我的经验,我个人使用它进行实时图像处理,在非阻塞线程中进行对象检测,然后Node.js将检测到的质心分发给连接的TCP客户端(该客户端使用数据驱动电机向检测到的对象移动)。
    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);
        })
    }