Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.0 nodejs基础知识总结 #6

Open
OhNaNaSun opened this issue Sep 16, 2016 · 3 comments
Open

1.0 nodejs基础知识总结 #6

OhNaNaSun opened this issue Sep 16, 2016 · 3 comments

Comments

@OhNaNaSun
Copy link
Owner

浅析 NodeJs 的几种文件路径

@OhNaNaSun OhNaNaSun changed the title nodejs路径&文件系统 home.js&nodejs路径&文件系统 Sep 16, 2016
@OhNaNaSun
Copy link
Owner Author

OhNaNaSun commented Oct 17, 2016

node特点

参考:关于node.js的误会

1、 js单线程,node多线程

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

node.js利用Google的V8 Javascript 引擎来解析JavaScript语句,但系统真正调用执行的代码是用C++写的,我们做的只是用JavaScript语句来调用这些底层API,所以不用担心其执行效率过低问题.

2、 异步I/O让单线程远离阻塞,使其适合于密集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();
});

2.1 CPU密集型任务

进程 vs. 线程
计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。

2.2 IO密集型任务,比如Web应用

参考:进程 vs. 线程
IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务(比如ajax),这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。
参考:Node.js软肋之CPU密集型任务
Web站点早已不仅限于内容的呈现,很多交互性和协作型环境也逐渐被搬到了网站上,而且这种需求还在不断地增长。这就是所谓的数据密集型实时(data-intensive real-time)应用程序,比如在线协作的白板,多人在线游戏等,这种web应用程序需要一个能够实时响应大量并发用户请求的平台支撑它们,这正是Node.js擅长的领域。
参考:Node.js软肋之CPU密集型任务

3、事件驱动

事件驱动的实质:通过主循环加事件触发的方式来运行程序。

大多数网站的服务器端都不会做太多的计算,它们只是接收请求,交给其它服务(比如文件系统或数据库),然后等着结果返回再发给客户端。所以聪明的Node.js针对这一事实采用了第二种策略,它不会为每个接入请求繁衍出一个线程,而是用一个主线程处理所有请求。避开了创建、销毁线程以及在线程间切换所需的开销和复杂性。这个主线程是一个非常快速的event loop,它接收请求,把需要长时间处理的操作交出去,然后继续接收新的请求,服务其他用户。下图描绘了Node.js程序的请求处理流程:
image

主线程event loop收到客户端的请求后,将请求对象、响应对象以及回调函数交给与请求对应的函数处理。这个函数可以将需要长期运行的I/O或本地API调用交给内部线程池处理,在线程池中的线程处理完后,通过回调函数将结果返回给主线程,然后由主线程将响应发送给客户端。那么event loop是如何实现这一流程的呢?这要归功于Node.js平台的V8引擎和libuv。

@OhNaNaSun
Copy link
Owner Author

OhNaNaSun commented Oct 17, 2016

Node.js的模块载入方式与机制
深入浅出Node.js(三):深入Node.js的模块机制

在Node中引入模块

采用缓存

不论是核心模块还是文件模块,require()方法对相同的模块的二次加载都一律采用缓存优先的方式

没有缓存,需要经历如下3个步骤

1、 路径分析

  • 核心模块:在node的源代码编译过程中已经编译成二进制代码,加载过程最快
  • 路径形式的模块 :"..""."开始的相对路径和"/"开始的绝对路径
  • 自定义模块:一个文件或包的形式,这类模块的查找是最费时的。node_modules

2、 文件定位

  • 扩展名分析
  • 目录分析和包

3、 编译执行

每一个编译成功的模块都会将其文件路径作为索引缓存在Module._cache对象上,以提高二次引用的性能。
每个模块之前都进行了作用域隔离
编译过程中,Node对获取的JavaScript文件内容进行了头尾包装。一个正常的js文件会被包装成这个样子:

(function(exports, require, module, __filename, __dirname){
    var math = require("math");
    exports.area = function(radius){
        return Math.PI * radius * radius
    }
})

@OhNaNaSun
Copy link
Owner Author

OhNaNaSun commented Oct 19, 2016

该不该用nodejs

不用
image

es6
image

image
image

@OhNaNaSun OhNaNaSun changed the title home.js&nodejs路径&文件系统 nodejs基础知识总结 Nov 16, 2016
@OhNaNaSun OhNaNaSun changed the title nodejs基础知识总结 1.0 nodejs基础知识总结 Nov 16, 2016
@OhNaNaSun OhNaNaSun mentioned this issue Dec 1, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant