Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.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
Node.js事件循环_Node.js_Loops_Events - Fatal编程技术网

Node.js事件循环

Node.js事件循环,node.js,loops,events,Node.js,Loops,Events,Node.js I/O事件循环是单线程还是多线程 若我有几个I/O进程,node会将它们放在一个外部事件循环中。它们是按顺序处理的(最快的优先)还是处理事件循环以同时处理它们(…以及在哪些限制中) 事件循环 Node.js事件循环在单个线程下运行,这意味着您编写的应用程序代码在单个线程上进行计算。Nodejs本身通过libuv使用许多线程,但在编写Nodejs代码时,您永远不必处理这些线程 每个涉及I/O调用的调用都需要注册回调。此调用也会立即返回,这允许您并行执行多个IO操作,而无需在应用程序

Node.js I/O事件循环是单线程还是多线程


若我有几个I/O进程,node会将它们放在一个外部事件循环中。它们是按顺序处理的(最快的优先)还是处理事件循环以同时处理它们(…以及在哪些限制中)

事件循环

Node.js事件循环在单个线程下运行,这意味着您编写的应用程序代码在单个线程上进行计算。Nodejs本身通过libuv使用许多线程,但在编写Nodejs代码时,您永远不必处理这些线程


每个涉及I/O调用的调用都需要注册回调。此调用也会立即返回,这允许您并行执行多个IO操作,而无需在应用程序代码中使用线程。一旦I/O操作完成,它的回调将被推送到事件循环上。它将在执行之前在事件循环上推送的所有其他回调都被执行时立即执行

有几种方法可以对如何将回调添加到事件循环进行基本操作。 通常你不应该需要这些,但有时它们会很有用

在任何时候都不会有两条真正的并行执行路径,因此所有操作本质上都是线程安全的。通常会有几个由事件循环管理的异步并发执行路径

限制

由于事件循环,节点不必为每个传入的tcp连接启动新线程。这允许节点并发服务,只要您不计算每个请求的前1000个素数

这也意味着不要执行CPU密集型操作,因为这些操作将锁定事件循环,并阻止其他异步执行路径继续。 同样重要的是,不要使用所有I/O方法的
sync
变体,因为这些方法也会锁定事件循环

如果你想做CPU密集型的事情,你应该把它委托给一个不同的进程,这个进程可以更有效地执行CPU绑定的操作,或者你可以把它作为一个进程来写

控制流

为了管理编写许多回调,您可能需要使用控制流库。 我相信这是目前最流行的基于回调的库:

我使用过回调,它们几乎让我发疯,我在使用承诺方面有更好的经验,bluebird是一个非常受欢迎的快速承诺库:

我发现这在节点社区中是一个非常敏感的话题(回调vs承诺),所以无论如何,使用你认为对你个人最有效的方法。一个好的控制流库还应该为您提供异步堆栈跟踪,这对于调试非常重要

当事件循环中的最后一个回调完成其执行路径并且不注册任何其他回调时,Node.js进程将完成

这不是一个完整的解释,我建议您查看以下线程,它是最新的:

威廉的回答是:

Node.js事件循环在单个线程下运行。每次I/O调用都需要注册回调。每个I/O调用也会立即返回,这允许您在不使用线程的情况下并行执行多个IO操作

我想用上面的这句话开始解释,这是我随处可见的对NodeJS框架的常见误解之一

Node.js不会神奇地用一个线程处理所有这些异步调用,并且仍然保持该线程的畅通。它在内部使用google的V8引擎和一个名为libuv(用c++编写)的库,该库使它能够将一些潜在的异步工作委托给其他工作线程(有点像等待主节点线程委托任何工作的线程池)。然后,当这些线程完成执行时,它们调用回调,这就是事件循环如何知道工作线程的执行已完成的事实

nodejs的要点和优点是,您永远不需要关心那些内部线程,它们将远离您的代码!。通常在多线程环境中发生的所有讨厌的同步内容都将被nodejs框架抽象出来,您可以在更友好的程序员环境中愉快地处理单线程(主节点线程)(同时受益于多线程的所有性能增强)

如果有人感兴趣,下面是一个很好的帖子:

为了了解事件循环,您必须首先了解nodeJs实现。 实际上,节点js核心实现使用两个组件:

  • v8 javascript运行时引擎

  • libuv用于handlign非i/o阻塞操作,并为您处理线程和并发操作

使用javascript,您实际上可以使用一个线程编写代码,但这并不意味着您的代码可以在一个线程上执行,尽管您可以使用节点js中的集群在多个线程上执行

现在,当您想要执行一些代码时,如:
让fs=require('fs');
fs.stat('path',(err,stat)=>{
//用统计数据做点什么;
console.log('second');
});

console.log('first')要理解事件中的nodejs I/O事件,必须正确理解nodejs事件循环

从名称event loop中,我们了解到它是一个循环,在循环中循环运行一个又一个循环,直到循环中没有事件或应用程序关闭为止

事件循环是nodejs中最重要的特性之一,它是nodejs中异步编程的基础

当程序启动时,我们处于事件循环运行的单线程中的节点进程中。现在我们最重要的事情
const fs = require('fs');
setTimeout(()=>console.log('Timer 1 finished'), 0);
fs.readFile('test-file.txt', ()=>{
    console.log('I/O finished');
});
setImmediate(()=>console.log('Immediate 1 finished'))
console.log('Hello from the top level code');
const fs = require('fs');
setTimeout(()=>console.log('Timer 1 finished'), 0);
setImmediate(()=>console.log('Immediate 1 finished'));

fs.readFile('test-file.txt', ()=>{
    console.log('I/O finished');
    setTimeout(()=>console.log('Timer 2 finished'), 0);
    setImmediate(()=>console.log('Immediate 2 finished'));
    setTimeout(()=>console.log('Timer 3 finished'), 0);
    setImmediate(()=>console.log('Immediate 3 finished'));
});
console.log('Hello from the top level code')

setTimeout(()=>console.log('Timer 1 finished'), 0);
setImmediate(()=>console.log('Immediate 1 finished'));

fs.readFile('test-file.txt', ()=>{
    console.log('I/O finished');
    setTimeout(()=>console.log('Timer 2 finished'), 3000);
    setImmediate(()=>console.log('Immediate 2 finished'));
    setTimeout(()=>console.log('Timer 3 finished'), 0);
    setImmediate(()=>console.log('Immediate 3 finished'));
});
console.log('Hello from the top level code')
setTimeout(()=>console.log('Timer 1 finished'), 0);
setImmediate(()=>console.log('Immediate 1 finished'));

fs.readFile('test-file.txt', ()=>{
    console.log('I/O finished');
    setTimeout(()=>console.log('Timer 2 finished'), 3000);
    setImmediate(()=>console.log('Immediate 2 finished'));
    setTimeout(()=>console.log('Timer 3 finished'), 0);
    setImmediate(()=>console.log('Immediate 3 finished'));
    process.nextTick(()=>console.log('Process Next Tick'));
});
console.log('Hello from the top level code')
console.log('starting')
setTimeout(()=>{
    console.log('0sec')
}, 0)
setTimeout(()=>{
    console.log('2sec')
}, 2000)
console.log('end')
starting 
0sec
end 
2sec 
starting 
end 
0sec 
2sec