Node 初探异步编程

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

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

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

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

   异步: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时注册的函数。

时间: 2024-08-01 04:44:37

Node 初探异步编程的相关文章

深入理解node.js异步编程

1. 概述目前开源社区最火热的技术当属Node.js莫属了,作为使用Javascript为主要开发语言的服务器端编程技术和平台,一开始就注定会引人瞩目. 当然能够吸引众人的目光,肯定不是三教九流之辈,必然拥有独特的优势和魅力,才能引起群猿追逐.其中当属异步IO和事件编程模型,本文据Node.js的异步IO和事件编程做深入分析. ##2. 什么是异步同步和异步是一个比较早的概念,大抵在操作系统发明时应该就出现了.举一个最简单的生活中的例子,比如发短信的情况会比较好说明他们的区别:同步:正在处于苦逼

七:初探异步编程

同步编程 创建类 using System; using System.Diagnostics; namespace TestAsyncConsole { public class NormalClass { Stopwatch sw = new Stopwatch(); public void DoSomething() { const int largeNumber = 600000; sw.Start(); int t1 = CountChar(1,largeNumber); int t2

初探asp.net异步编程

终于毕业了,也顺利进入一家期望的旅游互联网公司.27号入职.放肆了一个多月没写代码,好方啊. 写在前面(带着问题学习) 一.根据代码和执行结果,初探异步编程的执行过程. *问题1:await会让当前线程一直等待吗? *问题2:等待await数据返回交给等待线程再继续向下执行吗? *问题3:向await下一条语句执行的线程,是执行await的线程吗? 二.异步编程async,await的使用意义和适用场景. *问题1:异步编程可以让程序变快吗? *问题2:异步编程执行耗时计算有用吗? *问题3:既

node 单线程异步非阻塞

链接:http://www.runoob.com/nodejs/nodejs-callback.html 首先什么是单线程异步非阻塞? 单线程的意思整个程序从头到尾但是运用一个线程,程序是从上往下执行的.异步操作就是程序虽然是从上到下执行的,但是某个函数执行时间过长时并不会阻塞在那里等待它执行完,然后在执行下面的代码.非阻塞也就是这个意思. 为什么node是异步非阻塞的呢,得力于回调函数,还有js中的定时器也是经典的异步操作. ###4.1 Node.js异步机制 由于异步的高效性,node.j

4,异步编程

今天主要了解Node的异步编程思想. Node的异步编程,主要依托于回调来实现:但是这不意味着使用了回调程序就异步了. 举例: function heavyCompute(n, callback) {     var count = 0,         i, j; for (i = n; i > 0; --i) {         for (j = n; j > 0; --j) {             count += 1;         }     } callback(count)

【Node.js基础篇】(七)Node异步编程之事件发射器

事件发射器是Node里除了回调函数外的另一十分重要的异步编程技术. 在MFC等图形界面编程库中,事件发射器是非常常见的,比如,鼠标点击事件,点击了鼠标后,就会触发鼠标点击后的函数--事件发射器触发事件,并且在事件被触发后处理它们.在Node API组件中,如HTTP服务器.TCP服务器等都被做成了事件发射器,所以掌握事件发射器的编程方法,是非常重要的. 使用on添加监听器 步骤: 声明事件发射器类 创建事件发射器对象 使用on添加事件发射器 使用emit发射事件 //事件发射器类声明 var E

node 异步编程

node 异步编程 我了解到的node异步编程可分成: 1.回调函数 2.pub/sub模式(发布/订阅模式) 3.promise 4.generator 5.async await 一.直接回调函数 该方法是最直接常用的异步操作方式,比如在setInterval 和 ajax等会使用到, 存在缺点有: 1.代码不易阅读并且容易出现金字塔嵌套问题; 2.一般只能对应一个回调函数(一对一),使用上有一定的限制; fs.readFile('/etc/passwd', function (err, d

Node.js学习笔记【3】NodeJS基础、代码的组织和部署、文件操作、网络操作、进程管理、异步编程

一.表 学生表 CREATE TABLE `t_student` ( `stuNum` int(11) NOT NULL auto_increment, `stuName` varchar(20) default NULL, `birthday` date default NULL, PRIMARY KEY  (`stuNum`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 学生分数表 CREATE TABLE `t_stu_score` ( `id` int(11

Node.js学习笔记(2)——关于异步编程风格

Node.js的异步编程风格是它的一大特点,在代码中就是体现在回调中. 首先是代码的顺序执行: function heavyCompute(n, callback) { var count = 0, i, j; for (i = n; i > 0; --i) { for (j = n; j > 0; --j) { count += 1; } }callback(count); } heavyCompute(10000, function (count) { console.log(count)