• Node.js中的异步到底是个啥?


    Node.js 事件循环

    Node.js是单进程单线程应用程序,但是因为是V8引擎(from google,性能非常高)提供的异步执行回调接口,通过这些接口,可以处理大量的并发。

    Node.js 几乎每一个API都支持回调函数。

    Node.js 基本上所有的事件机制都是用设计模式中的观察者模式实现。

    Node.js 单线程类似进去一个while(true)的事件循环,直到没有事件观察者退出,每一个异步事件都生成一个事件观察者,如果有事件发生,就调用该回调参数。

    通俗的,就把每一个事件想象成一个一个先后启动windows后台程序(内存条很大,可以同时运行多个程序),比如浏览器,qq,微信,LOL,所不同的是,我们这里假象这些程序都会在运行不等时长后自动退出,并且在退出的瞬间,还会弹出提示。 那么做一下设想:

    //依次启动 :
    1.浏览器,
    2.qq,
    3.微信,
    4.LOL
    
    //运行时长:
    浏览器(15s),
    qq(5s),
    微信(9s),
    LOL(1s)
    
    //退出提示:
    1. 退出 LOL,
    2. 退出qq,
    3. 退出微信,
    4. 退出浏览器,
    

    以上过程,是异步的执行过程,我们可以把异步执行理解为多开后台,可以同时执行程序(内存条大),那么总共耗时15秒。 如果不是异步的话,那么就会产生阻塞,也就是会按照执行顺序一个个执行,上一个执行完毕,才执行下一个,相当于电脑的后台只能同一时间跑一个程序(内存小到爆炸的破电脑),那么阻塞执行的时长就会是:15s + 5s + 9s + 1s = 30s。

    下图作为参考:

    Node.js 回调函数

    在Node.js中,由于JavaScript的语言特性,所以实现异步编程的直接体现就是回调。

    但是,并不能说使用了回调之后程序就异步化了。回调函数在完成任务后就会被回调,Node使用了大量的回调函数,Node所有的API都支持回调函数。

    回调有什么作用?有什么需求?或者说有什么好处呢?

    通过回调函数,我们可以一边读取文件,一边执行其他的命令,在文件读取完成之后,我们将文件内容作为回调函数的参数返回。这样在执行代码的时候,就不会存在阻塞,或者等待文件I/O操作。这就大大提高了Node.js的性能。可以处理大量的并发请求。

    一段经典的阻塞与非阻塞代码实例:

    创建一个text文件,我们尝试用回调和不使用回调读取它。

    阻塞

    js

    var fs = require('fs');
    var data = fs.readFileSync('hello.txt');
    
    console.log(data.toString());
    console.log('done');
    

    bash

    我是中国人
    “I'm from China, I love my country!”
    done
    

    异步:

    js

    var fs = require('fs');
    fs.readFile('hello.txt',function(err,data){
    	if(err) return console.log(err);
    	console.log(data.toString());
    });
    console.log('done');
    

    bash

    done
    我是中国人
    “I'm from China, I love my country!”
    

    简单的说,因为读取文件,需要进行I/O操作,因此相对会花费更多的时间。 我们可以形象的理解为,通过异步操作,我们先开启文件读取操作,但是把它挂在后台执行,执行期间,由于直接打印'done'要消耗的时间小的多,所以整个程序将会先直接打印'done',然后程序会打印挂起执行的文件读取返回结果。

    为了更直观的说明异步执行,我们将同样的逻辑代码,读取两个大小不同的文件:

    var fs = require('fs');
    //注意,下面两段代码,写在前面的文本文件占用空间更大。
    fs.readFile('compareText2.txt',function(err,data){
    	if(err) return console.log(err);
    	console.log("-----这个文本更长一些-----");
    	console.log(data.toString());
    	console.log("-----这个文本更长一些-----");
    	console.log("done,
    compareText2.txt");
    });
    
    
    fs.readFile('compareText1.txt',function(err,data){
    	if(err) return console.log(err);
    	console.log("#####这个文本更短一些#####");
    	console.log(data.toString());
    	console.log("#####这个文本更短一些#####");
    	console.log("done,
    compareText1.txt");
    });
    

    bash

    #####这个文本更短一些#####
    -----LINE5-----
    "我是中国人"
    "我是中国人"
    "我是中国人"
    "我是中国人"
    "我是中国人"
    -----LINE5-----
    
    #####这个文本更短一些#####
    done,
    compareText1.txt
    -----这个文本更长一些-----
    -----LINE150-----
    "我是中国人"
    "我是中国人"
    "我是中国人"
    //.......
    //......共150行
    //......
    "我是中国人"
    -----LINE150-----
    
    -----这个文本更长一些-----
    done,
    compareText2.txt
    
    

    我们发现读取大文件的逻辑写在前面,但是却后输出。 代码的执行过程是这样的:先触发执行读取大文件的函数,然后挂起,然后触发执行读取小文件的函数,由于小文件内容少,更快执行完,所以小文件读取函数的返回值返回的更快,于是小文件读取的返回结果更快被打印出来。

  • 相关阅读:
    linux指令大全
    strcpy.strcmp.strlen.strcat函数的实现
    推箱子
    头文件string.h里的函数
    SVN 版本控制工具
    Nodejs 学习
    JavaScript基础知识复习
    CSS3 学习小结
    JSP中 JSTL
    JSP中的EL语言
  • 原文地址:https://www.cnblogs.com/jaycethanks/p/12741915.html
Copyright © 2020-2023  润新知