深入浅出node笔记(一)

1、

require http创建服务器,使用createServer方法接受客户端的请求以及响应请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var http = require('http') ;
var querystring = require('querystring');
//侦听服务器的request事件
http.createServer(function (req,res){
var postData = '';
req.setEncoding('utf8’);
//侦听请求的data事件
req.on('data', function (chunk){
postData += chunk;
});
//侦听请求的end事件
req.on('end', function({
res.end(postData);
});

单线程

node同js一样也是单线程,单线程最大的好处在于不用像多线程一样,时刻在意线程间的同步问题,没有死锁。缺点在于无法利用多核CPU、错误可能会导致整个应用的崩溃、node的大量计算占用CPU导致无法继续调用异步IO。

与JS的web workers类似,node使用child_process来解决单线程中大量计算的问题。通过将计算分发给子进程,将大量计算分解掉,然后通过进程间的通信传递结果。

应用场景

IO密集型:利用事件循环处理,而不是一个线程处理一个请求。

CPU密集型:虽然是单线程,但是可以通过下面两种方法来充分利用CPU:

  • 通过编写C/C++拓展更高效利用CPU。
  • 通过子进程的方式,将一部分node作为常驻服务进程用于计算,利用进程通信传递结果。

分布式应用

分布式应用是指可以同时在多个系统中运行,通过协调来快速完成任务。对可伸缩性要求很高,可伸缩性是指当性能需要增加时,可以添加多台机器而不会停机。正在运行的系统称为集群。像阿里巴巴的数据平台就是使用node实现分布式应用。

二、模块

CommonJS的愿望是,在任何地方都能运行JS🎇

使用require来引入模块,exports导出当前模块的方法或变量,每个模块具有独立空间,引用时显得干净利落。

在node中引用模块经过三步:路径解析,文件定位,编译执行。模块之间的依赖关系如下:文件模块可能依赖核心模块(JS),核心模块可能依赖于内建模块(C/C++)。不推荐文件模块直接调用内建模块,这些在核心模块中都可能已经封装好了。

前面提到C/C++扩展能提高CPU的利用,比如说JS对位运算的支持,由于JS只有double的数据类型,还得转换为int型,这里就可以使用C/C++来实现。

包与NPM

commonJS中包由包结构和包描述组成,包结构指解压后由特定结构组成:package.json描述文件,lib存放js文件,bin存放二进制文件等等。包描述就是package.json文件,主要包含包的相关信息的字段,NPM与字段息息相关。

前后端共用模块

前端的JS需要经历从同一个服务器分发到多个客户端执行,瓶颈在于带宽,后端的JS是同一段代码运行多次,瓶颈在于CPU和内存,两者加载速度不在同一个数量级上。node中模块的引入是同步的,可是前端模块只能异步引入,不能让UI等待脚本执行完。

于是产生了AMD(异步模块定义),需用define来定义模块,并且在定义模块时就要声明所有依赖。

CMD定义模块时,动态引入依赖,需要的时候再去引入。

异步IO

异步IO是为了实现,调用IO而不影响运算。

书中首先写的是操作系统的异步IO,这里就不多介绍了。

node中的异步IO与事件循环、IO线程池、观察者、请求对象相关。

首先发起一个异步调用的请求,封装请求对象,设置参数和回调函数,最后将请求对象放入进程池中,至此异步调用阶段结束。进入线程池后,分配线程执行任务,将结果写入请求对象中。继续事件循环。

事件循环是指,查看是否有事件要处理,有的话查看事件是否有关联回调,有的话就执行回调,再查看是否有事件要处理,没有事件就退出。通过观察者询问,判断是否有事件要处理。

线程池:系统在启动时创建大量空闲线程,程序将一个任务传给线程池,线程池分配给某线程,线程执行完后进入空闲状态而不会死亡。

异步API

setTimeout与setInterval都是定时器,区别在于一次或多次定时执行任务。定时器的实现原理:被插入定时器观察者中的红黑树中,每次tick时会迭代检查定时器对象是否超时,超时就立即执行回调函数。

这样的缺点在于:当某个循环占用过多的时间,事件循环会延迟,导致定时器超时很久。

process.nextTick()较定时器更轻量,process.nextTick将回调函数放入队列中延迟执行,每次tick取出执行。

setImmediate类似process.nextTick,将回调函数放入队列中延迟执行。但优先级比process.nextTick低,因为在事件循环中idle观察者先于IO观察者,IO观察者先于check观察者。process.nextTick属于idle观察者,setImmediate属于check观察者。

事件驱动

事件驱动的本质是,通过主循环的事件来运行程序。

对于网络套接字的处理也用到了异步IO,服务器收到网络请求形成事件后发送给IO观察者,事件循环处理这些事件,如果有业务层的回调,JS执行回调。

image-20210107144841613
查看评论