Node.js基础与实战

时间:2022-09-03 18:27:22

Node.js基础与实战

Node.jsJS高级进阶
 NODE原理与解析
 REPL交互环境
 模块与NPM
 Buffer缓存区
 fs文件操作
 Stream流
 TCP&UDP
 异步编程
 HTTP&HTTPS
 进程与集群
 网络安全

关于node.js的误会

昨天写了篇博客,介绍了一下我对node.js的第一次亲密接触后的感受,以为node.js很小众,出乎我意料很多人感兴趣,并且对博客中的细节问题做了评论,最多的是围绕node.js的异步与单线程展开的,当然还有很多关于node.js究竟是不是语言?不是的话又是什么。。。之类的问题,其实刚接触node.js,了解的并不是很深入,越是回复大家问题,心里越是没底,决定认真研究一下,经人指点看了一下《Node.js开发指南》发现大部分问题都有了答案,权当一个读书笔记把问题答案分享出来,希望可以帮到一些和我一样才接触node.js的小菜

关于单线程一个由来已久的误会

在上篇博客中提到我们使用node.js写的JavaScript代码是单线程运行的,让很多同学很疑惑,单线程怎么实现异步操作,单线程谁去响应事件。。。在html5 Web Workers中我也有提到过客户端的JavaScript也是单线程运行的,大家明显没有这么大反应,还是普遍能接受的。可单线程的客户端JavaScript也能响应DOM事件,还有大家都很熟悉的ajax操作,回调函数也是异步的,既然客户端JavaScript是单线程执行的,回调函数是谁调用的呢?答案很简单,JavaScript的宿主环境——浏览器,也就是说虽然JavaScript是单线程执行的,但浏览器是多线程的,负责调度管理JavaScript代码,让它们在恰当的时机执行。

所以我们所说的node.js单线程,是指node.js并没有给我们创建一个线程的能力,所有我们自己写的代码都是单线程执行的,在同一时间内,只能执行我们写的一句代码。但宿主环境node.js并不是单线程的,它会维护一个执行队列,循环检测,调度JavaScript线程来执行。因此单线程执行和并发操作并不冲突。

阻塞与线程

什么叫阻塞(block)?线程在执行中如果遇到I/O操作(磁盘读写、网络通信等)通常需要耗费较长的时间,这时候操作系统会剥夺线程对CPU的控制权,使其暂停,并把资源让给其它的工作线程,这种线程调度方式成为阻塞。当I/O操作完毕的时候操作系统将这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行,这种I/O模式就是同步I/O或成为阻塞I/O。

响应的异步I/O或非阻塞I/O则针对所有的I/O操作采取不阻塞的策略,当线程遇到I/O操作时不会以阻塞的方式等待I/O操作结束,而只是将I/O请求发送给操作系统,继续执行后续语句。当操作系统完成I/O操作时以事件的形式通知执行I/O操作的线程,线程会在特定时间处理这个事件。为了处理异步I/O必须有事件循环,不断检查有没有未处理的事件,依次予以处理。

在阻塞模式下,一个线程只能处理一个任务,要想提高吞吐量必须通过多线程。而在非阻塞模式下一个线程永远在执行计算操作,这个线程所使用的CPU核心利用率永远是100%,I/O以事件的方式通知。在阻塞模式下多线程往往能够提高系统吞吐量,因为一个线程阻塞时还有其他线程在工作,多线程何以让CPU资源不被阻塞的线程浪费。而在非阻塞模式下,线程不会被I/O阻塞,永远在利用CPU。异步I/O减少了多线程中创建线程、分配内存、列入调度、切换线程、内存换页、CPU缓存等方面的开销。

事件循环机制

上面提到了几次事件循环机制,那么这个听起来貌似很高端的东东究竟是什么呢?所谓事件循环是指node.js会把所有的异步操作使用事件机制解决,有个线程在不断地循环检测事件队列。node.js中所有的逻辑都是事件的回调函数,所以node.js始终在事件循环中,程序入口就是事件循环第一个事件的回调函数。事件的回调函数中可能会发出I/O请求或直接发射( emit)事件,执行完毕后返回事件循环。事件循环会检查事件队列中有没有未处理的事件,直到程序结束。node.js的事件循环对开发者不可见,由libev库实现,libev不断检查是否有活动的、可供检测的事件监听器,直到检查不到时才退出事件循环,程序结束。

Node.js基础与实战

node.js是什么?和JavaScript有什么关系?

关于node.js究竟是什么,大家的问题在于

  1. node.js是不是一门语言?
  2. node.js是不是一个JavaScript库函数?
  3. node.js是不是一个JavaScript框架?

很遗憾,这三个问题的答案都是NO,看看官方对自己的描述

Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

官方很明确地说node.js是一个platform,也就是一个做xxx的平台。node.js是一个可以在服务器端运行JavaScript的平台,其实这句话华也不准确,按照《JavaScript权威指南》《JavaScript高级程序设计》等书中的定义,JavaScript是由两部分组成

  1. core JavaScript
  2. client JavaScript(DOM、BOM)

而只有core JavaScript可以在node.js上运行,所以node.js借用了JavaScript的语法,但并不能用来处理浏览器对象(BOM)及文档对象(DOM),所以node.js并不是设计为在服务器端运行解析html文档的(当然有module可以做此事),所以“在服务器端运行的JavaScript”在一定程度上误导了初学者。

同时node.js并不仅仅运行core JavaScript,node.js中还有文件系统、模块包、操作系统API、网络通信、二进制类型处理等core JavaScript不具备的功能。

node.js是在执行JavaScript语句吗

从字面意思上是的,因为我们在使用node.js开发的时候写的确实是JavaScript语句,而且node.js利用Google的V8 Javascript 引擎来解析JavaScript语句,但系统真正调用执行的代码是用C++写的,我们做的只是用JavaScript语句来调用这些底层API,所以不用担心其执行效率过低问题

异步I/O与事件驱动

毫不夸张的说node.js最大的特定就是采用异步I/O和事件驱动架构,对于高并发解决方案传统架构师多线程模型,为每个业务逻辑童工一个线程,通过系统线程切换来来弥补同步I/O调用的时间开销。node.js使用的是单线程模型,对所有I/O都采用异步式的请求方式,避免频繁的上下文切换,在node.js执行的时候维护着一个事件队列,程序在执行时进入事件循环等待下一个事件到来,每个异步I/O请求完成后都会被推送到事件队列中的等待执行。

对于一个简单的数据库访问操作,传统方式是这样实现的

 res = db.query('SELECT * from some_table');
res.output();

代码执行到第一行的时候线程会阻塞,等待query返回结果,然后继续处理。由于数据库查询、磁盘读写、网络通信等原因阻塞时间会非常大(相对于CPU始终频率)。对于高并发的访问,一方面线程长期阻塞等待,另一方面为了应付新情求而不断添加新线程,会浪费大量系统资源,同时线程的增加也会也会占用大量的CPU时间来处理内存上下文切换。看看node.js怎么处理

db.query('SELECT * from some_table', function(res) { 
res.output();
});

在代码中熟悉Javascript的同学一眼就可以看明白query的第二个参数是一个回调函数,进程执行到db.query的时候不会等待结果返回,而是直接继续执行下面的语句,直到进入事件循环。当数据库执行结果返回的时候会将事件发送到事件队列,等到线程进入事件循环后才会调用之前的回调函数。

node.js的异步机制是基于事件的,所有的I/O、网络通信、数据库查询都以非阻塞的方式执行,返回结果由事件循环来处理。node.js在同一时刻只会处理一个事件,完成后立即进入事件循环检查后面事件。这样CPU和内存在同一时间集中处理一件事,同时尽量让耗时的I/O等操作并行执行。

node.js架构

node.js用异步式I/O和事件驱动代替多线程提升性能,除了使用高效的V8作为JavaScript引擎外还使用了高效的libev和libeio库支持事件驱动和异步I/O。

Node.js基础与实战

node.js作者在libeio和libev的基础上抽象出了libuv层,对于POSIX(Portable Operating System Interface 是一套操作系统API规范,遵循的有Unix、Linux、Mac OS X等)操作系统libuv通过封装libev和libio来利用epoll或kqueue。而在Windows下libuv使用了IOCP(Input/Output Completion Port,输入输出完

Node.js基础与实战的更多相关文章

  1. node.js基础模块http、网页分析工具cherrio实现爬虫

    node.js基础模块http.网页分析工具cherrio实现爬虫 一.前言      说是爬虫初探,其实并没有用到爬虫相关第三方类库,主要用了node.js基础模块http.网页分析工具cherri ...

  2. Node.js基础知识

    Node.js入门   Node.js     Node.js是一套用来编写高性能网络服务器的JavaScript工具包,一系列的变化由此开始.比较独特的是,Node.js会假设在POSIX环境下运行 ...

  3. NodeJs>------->>第三章:Node.js基础知识

    第三章:Node.js基础知识 一:Node.js中的控制台 1:console.log.console.info  方法 console.log(" node app1.js 1> ...

  4. 10慕课网《进击Node.js基础(一)》初识promise

    首先用最简单的方式实现一个动画效果 <!doctype> <html> <head> <title>Promise animation</titl ...

  5. 进击Node&period;js基础(二)

    一.一个牛逼闪闪的知识点Promise npm install bluebird 二.Promise实例 ball.html <!doctype> <!DOCTYPE html&gt ...

  6. 07慕课网《进击Node&period;js基础(一)》HTTP小爬虫

    获取HTML页面 var http = require('http') var url='http://www.imooc.com/learn/348' http.get(url,function(r ...

  7. 03慕课网《进击Node&period;js基础(一)》API-URL网址解析

    url url.parse(url,query,host);解析域名 url必须,地址字符串 query可选 host 可选:在不清楚协议时正确解析 querystring 字符串和对象之间互相解析 ...

  8. 01慕课网《进击Node&period;js基础(一)》Node&period;js安装,创建例子

    版本:偶数位为稳定版本,基数为非稳定版本 - 0.6.x - 0.7.x    - 0.8.x -0.9.x    -0.10.x  -0.11.x 概念:Node.js采用谷歌浏览器的V8引擎,用C ...

  9. &lbrack;js高手之路&rsqb;Node&period;js&plus;jade&plus;mongoose实战todolist&lpar;分页&comma;ajax编辑&comma;删除&rpar;

    该系列文章索引: [js高手之路]node js系列课程-创建简易web服务器与文件读写 [js高手之路]node js系列课程-图解express+supervisor+ejs用法 [js高手之路] ...

随机推荐

  1. mysql-Federated存储方式,远程表,相当于sql server的linked server

    MySQL中针对不同的功能需求提供了不同的存储引擎.所谓的存储引擎也就是MySQL下特定接口的具体实现. FEDERATED是其中一个专门针对远程数据库的实现.一般情况下在本地数据库中建表会在数据库目 ...

  2. CSS学习笔记之定位

    position 有4中不同类型的定位,分别为static.relative.absolute.fixed 1.static 元素框正常生成.块级元素生成一个矩形框,作为文档流的一部分,行内元素则会创 ...

  3. Flex布局如何让子类在超出边界时隐藏掉

    在flex4中,因为必须添加<s:Scroller>标签才能出现滚动条,如果一个容器例如Panel没有添加滚动条,那么添加到Panel中的child的位置如果超出了Panel的边界,那么这 ...

  4. 自己动手实现智能指针auto&lowbar;ptr

    面试的时候,我们经常会被问到如何自己动手实现智能指针auto_ptr.今天我就一边参考STL库中的源代码,一边将auto_ptr的实现敲一遍. auto_ptr归根到底是一个模版类,那么这个类要实现哪 ...

  5. gridView 编辑单元格获取单元格焦点位置(位于单元格的焦点位置)

    1.主要代码: private void Form1_Load(object sender, EventArgs e) { DataTable dt = new DataTable(); dt.Col ...

  6. Coursera 机器学习笔记(四)

    主要为第六周内容机器学习应用建议以及系统设计. 下一步做什么 当训练好一个模型,预测未知数据,发现结果不如人意,该如何提高呢? 1.获得更多的训练实例 2.尝试减少特征的数量 3.尝试获得更多的特征 ...

  7. golang 互斥锁和读写锁

    golang 互斥锁和读写锁 golang中sync包实现了两种锁Mutex(互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能. ty ...

  8. 关于bootstrap报错

    在使用bootstrap报错.报错的位置如下 if("undefined"==typeof jQuery)throw new Error("Bootstrap's Jav ...

  9. Mybatis Generator代码自动生成(实体类、dao层、映射文件)

    写了一段时间增删改查有点厌烦,自己找了下网上的例子鼓捣了下自动生成. 首先得有一个配置文件: generatorConfig.xml <?xml version="1.0" ...

  10. docker1&period;13&period;1的安装与卸载及mysql5&period;5安装实例

    docker中国官方地址:https://www.docker-cn.com/ 您可以使用以下命令直接从该镜像加速地址进行拉取: $ docker pull registry.docker-cn.co ...