node 单线程异步非阻塞

连接:http://www.runoob.com/nodejs/nodejs-callback.htmlhtml

 

首先什么是单线程异步非阻塞?node

单线程的意思整个程序从头至尾可是运用一个线程,程序是从上往下执行的。异步操做就是程序虽然是从上到下执行的,可是某个函数执行时间过长时并不会阻塞在那里等待它执行完,而后在执行下面的代码。非阻塞也就是这个意思。linux

为何node是异步非阻塞的呢,得力于回调函数,还有js中的定时器也是经典的异步操做。程序员

###4.1 Node.js异步机制 因为异步的高效性,node.js设计之初就考虑作为一个高效的web服务器,做者理所固然地使用了异步机制,并贯穿于整个node.js的编程模型中,新手在使用node.js编程时,每每会羁绊于因为其余编程语言的习惯,好比C/C++,以为无所适从。咱们能够从如下一段简单的睡眠程序代码窥视出他们的区别,下面是摘自《linux程序设计》打印10个时间的C代码:web

#include <time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    int i;
    time_t the_time;
    for(i = 1; i <= 10; i++) {
        the_time = time((time_t *)0);
        printf("The time is %ld\n", the_time);
        sleep(2);
    }
    exit(0);
}

 

编译后打印结果以下:编程

The time is 1396492137服务器

The time is 1396492139并发

The time is 1396492141异步

The time is 1396492143编程语言

The time is 1396492145

The time is 1396492147

The time is 1396492149

The time is 1396492151

The time is 1396492153

The time is 1396492155

从C语言的打印结果能够发现,是隔2秒打印一次,按照C程序该有的逻辑,代码逐行执行。如下Node.js代码本意如同上述C代码,使用目的隔2秒打印一次时间,共打印10条(初次从C/C++转来接触Node.js的程序员可能会写出下面的代码):

function test() {
    for (var i = 0; i < 10; i++) {
        console.log(new Date);
        setTimeout(function(){}, 2000);    //睡眠2秒,而后再进行一下次for循环打印
    }
};
test();

 

打印结果: Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
Tue Apr 01 2014 14:53:22 GMT+0800 (中国标准时间)
观察结果发现都是在14:53:22同一个时间点打印的,根本就没有睡眠2秒后再执行下一轮循环打印!这是为何?从官方的文档咱们看出setTimeout是第二个参数表示逝去时间以后在执行第一个参数表示的callback函数,所以咱们能够分析, 因为Node.js的异步机制,setTimeout每一个for循环到此以后,都注册了一个2秒后执行的回调函数而后当即返回立刻执行console.log(new Date),致使了全部打印的时间都是同一个点,所以咱们修改for循环的代码以下:

for (var i = 0; i < 10; i++) {
setTimeout(function(){
console.log(new Date);
}, 2000);    

}

 

执行结果以下所示: Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:30:35 GMT+0800 (中国标准时间) 神奇,仍然是同一个时间点,见鬼!冷静下来分析,时刻考虑异步,for循环里每次setTimeout注册了2秒以后执行的一个打印时间的回调函数,而后当即返回,再执行setTimeout,如此反复直到for循环结束,由于执行速度太快,致使同一个时间点注册了10个2秒后执行的回调函数,所以致使了2秒后全部回调函数的当即执行。 咱们在for循环以前添加console.log("before FOR: " + new Date)和以后console.log("after FOR: " + new Date),来验证咱们的推测,打印结果以下(后面省略8条相同的打印行): before FOR: Thu Apr 03 2014 09:42:43 GMT+0800 (中国标准时间)
after FOR: Thu Apr 03 2014 09:42:43 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:42:45 GMT+0800 (中国标准时间)
Thu Apr 03 2014 09:42:45 GMT+0800 (中国标准时间) …… (省略与上一行8条相同的打印行) 由此能够窥视出Node.js异步机制的端倪了,在for循环中的代码于其后的代码几乎在一个单位秒内完成,而定时器中的回调函数则按要求的2秒以后执行,也是同一秒内执行完毕。那么如何实现最初C语言每隔2秒打印一个系统时间的需求函数呢,我实现了以下一个wsleep函数,放在for循环中,能够达到该目的:

function wsleep(milliSecond) { var startTime = new Date().getTime(); while(new Date().getTime() <= milliSecond + startTime) { } }

可是该函数有一个令他没法在项目中使用的缺陷,请问为何?

 

 

若是没有回调函数的话,就变成阻塞式的,程序基本上是从上到下执行的。主要就是由于回调函数的影响致使的

 

 

2.阻塞与非阻塞

Node.js 回调函数

Node.js 异步编程的直接体现就是回调。

异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。

回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 全部 API 都支持回调函数。

例如,咱们能够一边读取文件,一边执行其余命令,在文件读取完成后,咱们将文件内容做为回调函数的参数返回。这样在执行代码时就没有阻塞或等待文件 I/O 操做。这就大大提升了 Node.js 的性能,能够处理大量的并发请求。


阻塞代码实例

建立一个文件 input.txt ,内容以下:

菜鸟教程官网地址:www.runoob.com

建立 main.js 文件, 代码以下:

var fs = require("fs"); var data = fs.readFileSync('input.txt'); console.log(data.toString()); console.log("程序执行结束!");

以上代码执行结果以下:

$ node main.js 菜鸟教程官网地址:www.runoob.com 程序执行结束!

非阻塞代码实例

建立一个文件 input.txt ,内容以下:

菜鸟教程官网地址:www.runoob.com

建立 main.js 文件, 代码以下:

var fs = require("fs"); fs.readFile('input.txt', function (err, data) { if (err) return console.error(err); console.log(data.toString()); }); console.log("程序执行结束!");

以上代码执行结果以下:

$ node main.js 程序执行结束! 菜鸟教程官网地址:www.runoob.com 

以上两个实例咱们了解了阻塞与非阻塞调用的不一样。第一个实例在文件读取完后才执行完程序。 第二个实例咱们呢不须要等待文件读取完,这样就能够在读取文件时同时执行接下来的代码,大大提升了程序的性能。

所以,阻塞按是按顺序执行的,而非阻塞是不须要按顺序的,因此若是须要处理回调函数的参数,咱们就须要写在回调函数内。

相关文章
相关标签/搜索