Node 初探异步编程

从C/C++转过来最开始不适应的就是这个了吧。=-=html

Node是单线程,那么怎么提升效率?怎么解决一些阻塞问题?Node的基因里使用了异步IO,上次在http://www.cnblogs.com/zhangmingzhao/p/7564738.html 已经说到这个问题,Node的异步机制每每伴随着回调。java

先看一个关于CPU的例子来比较同步和异步:node

   同步:CPU须要计算10个数据,每计算一个结果后,将其写入磁盘,等待写入成功后,再计算下一个数据,直到完成。web

   异步:CPU须要计算10个数据,每计算一个结果后,将其写入磁盘,不等待写入成功与否的结果,马上返回继续计算下一个数据,计算过程当中能够收到以前写入是否成功的通知,直到完成。编程

如过没有异步,CPU写入磁盘等待返回的结果的等待时间也被无情的消耗了。来看一段代码:服务器

咱们期待的结果是1,可是结果确实0。为何呢?异步

这个就是node的异步机制。咱们先执行了plus,没有等2秒,而是直接运行下一句打印函数,此时的c值仍是0.编程语言

那怎么解决这个问题呢?函数

传入回调函数来解决。测试

咱们来给plus传入一个callback函数,以下:

运行结果,打印出1。

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

咱们来写一个Java的:

import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
    public static void main(String[] args) {
        int i;
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        for(i = 0; i < 10; i++) {
            System.out.println(df.format(new Date()));
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运用Java中线程的sleep来获得以下结果:

2017-09-22 18:53:41
2017-09-22 18:53:43
2017-09-22 18:53:45
2017-09-22 18:53:47
2017-09-22 18:53:49
2017-09-22 18:53:51
2017-09-22 18:53:53
2017-09-22 18:53:55
2017-09-22 18:53:57
2017-09-22 18:53:59

咱们把代码直译成Node版本:

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

咱们发现这个结果几乎是同时打印出来,2秒并无起到什么做用。

setTimeout的第二个参数表示该时间以后在执行第一个参数表示的callback函数。

所以咱们能够分析, 因为Node.js的异步机制,setTimeout每一个for循环到此以后,都注册了一个2秒后执行的回调函数而后当即返回立刻执行console.log(new Date),致使了全部打印的时间都是同一个点。然而这个函数仅仅是注册,空函数什么事都没作。那么我这样呢:

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

 

结果是等了2秒后,一会儿打印了10个

仍是异步特性,咱们能够这样理解,for循环里每次setTimeout注册了2秒以后执行的一个打印时间的回调函数,没有等2秒,而是当即返回,再执行setTimeout,如此反复直到for循环结束,由于执行速度太快,致使同一个时间点注册了10个2秒后执行的回调函数,而后for循环结束,所以致使了2秒后全部回调函数的当即执行。 

 

 继续测试,咱们加上 console.log("before FOR: " + new Date)和以后console.log("after FOR: " + new Date)

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

这个与一开始的例子差很少,中间的延迟不影响下面代码的运行。

before和after几乎在同一时刻运行

而定时器中的回调函数则按要求的2秒以后执行,也是同一秒内执行完毕。那么如何实现最初Java语言每隔2秒打印一个系统时间的需求函数呢,这样写,结果也能够达到要求:

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

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

 

 

可是在实际状况中是不会这么写的,这样阻塞了CPU20s的时间,而不能干其余事,异步的存在就是提升效率。

 

还有这样写可能会更帮助理解:

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

咱们发现打印的都是结果i为0时注册的函数。

相关文章
相关标签/搜索