在看Node.js开发指南的时候看到下面这段话:
看看Node.js是如何解决这个问题的: db.query(‘SELECT * from some_table’, function(res) { res.output(); }); 这段代码中 db.query 的第二个参数是一个函数,我们称为回调函数。进程在执行到 db.query 的时候,不会等待结果返回,而是直接继续执行后面的语句,直到进入事件循环。 当数据库查询结果返回时,会将事件发送到事件队列,等到线程进入事件循环以后,才会调 用之前的回调函数继续执行后面的逻辑。
但是看不懂这里说的:
进程在执行到db.query 的时候,不会等待结果返回,而是直接继续执行后面的语句,直到进入事件循环。
当数据库查询结果返回时,会将事件发送到事件队列,等到线程进入事件循环以后,才会调
用之前的回调函数继续执行后面的逻辑。
我个人的理解是: 所有的请求都是异步的,然后当所有的请求到达服务器的时候,对磁盘的I/O操作不会等待结果返回,而是直接执行回调函数,并不是直接返回给客户端,而是这时进入一个事件队列等待处理,而cpu和内存在同一时间只处理一件事,这个时候可能I/O操作已经得到返回值了,然后把返回结果也发送到刚才已经排在队列里面的回调函数,等到cpu处理到这里的时候它们已经有结果了,cpu就直接处理此事件, 打个比方: 客户端的请求就好比两个人A,B去买东西,A就是I/O,B就是回调函数,到达超市的时候A去货架上面选东西,而B这个时候并不和A一起去,而是一个人说我先去排队付款,你好了来找我我先占个位置,B就去排队了,而收银员在同一时间是只收取一个人的费用的,当A选完东西之后它会去找排队的B,一起排队等待收银员收取费用(也就是等待处理),收银员收取费用之后A,B就回家了,也就想当于处理了一次完整的请求返回给客户端,
不知道我的理解对不对?敬请各位大神指点下,
我是这样理解的: Nodejs Server 可以理解成对一个个请求的响应方法和一个队列. 对于不需要异步的请求,方法会直接返回这样一次请求就会结束, 如果需要IO, 数据库等比较耗时的操作就用异步的方式把他们放到队列里, 而响应请求的方法会立刻结束而不会阻塞其他的响应方法,从而加快服务器响应. 而在队里中的工作执行完成之后会返回给用户. 场景是这样的: 同时有两个请求A, B. A需要1000ms异步操作, B不需要异步. 假如A比B早1ms. 对于单线程的Node如果不用异步的方式, B需要在10001ms的时候才能拿到响应. 但是因为Node是异步的, 所以A请求到来时,需要花费1000ms的读取操作被放到了队列, B请求可以立刻得道处理,并返回结果. 等处理队列完成之后A用户会得道返回内容, A用户的等待时间还是1000ms. 这也是为什么Node可以采用单线程的原因. 对于A来说他还是需要等待1000ms, 但是A请求通过异步的方式不过影响其他请求. 在其他语言中这是通过多线程实现的. 但是在大量并发请求发生的时候, Nodejs的优势就会体现出来.
我想请问下的就是,如果B请求还有C、D、E、F…等,总共花费时间加起来大于A所需要的1000ms,这个时候A结果也已经返回回来了,进入队列等待了吧,此时是先将B后面的C、D、E、F…等执行完过后再执行回调函数呢还是,比如把D执行完了刚好超过了1000ms,此时就直接去队列执行A回调函数呢?也就是里面说的事件循环究竟是如何运行的?谢谢!
@pf12345,可以从以下一些方面来看
事件循环解析
三个问题
以上就是事件循环的实质,但是还有三个问题值得探讨
1. 假设事件队列本来为空,这时A, B两个事件相隔200ms发生,那么他们的回调例程是如何调度运行的呢?应该是这样:
OK, 没有意外的话,事件循环就这样一直的执行下去了,一切都很好。但是如果,A例程需要进行一些数据计算,执行时间大概需要500ms,那这时情况又是怎样的呢?应该是这样
从这里可以看出,如果A回调执行时间过长,会导致A,B回调的执行显得很连续,中间并不会间隔200ms左右
2. 所有的回调例程放入请求都会被事件队列接收吗?
答案是否,javascript引擎有点聪明,会保证事件队列中所有的例程实例都是不同的, 也就是说,在某些情况下,事件看起来好像会丢失!
3. javascript是单线程的吗?
不能简单的说是,且不说web workers的引入(当然是在browser端), 即使以我们前面的分析也可以看出,除了主线程之外,肯定还有另外的线程存在,比如将回调例程放入事件队列的那个线程。
当然,传统上,引擎暴露给我们的,我们能使用的就是主线程。