小细节
- node 是单线程的,(指的是node 中的js是单线程的),node自身是多线程的,利用的是线程池
- node 中采用,模块引用(require()),模块定义(AMD,CMD,node自身的隐式封装),模块标识(moudle.id)
- node 的封装:就是在函数用括号括起来
- AMD 是采用define(function(){})进行封装,采用返回值进行到处 (return exports.method();)
- CMD define(function(){})进行封装,require ,exports ,moudle,通过形参传递给函数,通过require()调用;
- parse()转化为对象,format 转化为字符串,resolve()进行 url 拼接
- 为什么通过headers对象访问到的HTTP请求头或响应头字段不是驼峰的?:
从规范上讲,HTTP请求头和响应头字段都应该是驼峰的。但现实是残酷的,不是每个HTTP服务端或客户端程序都严格遵循规范,所以NodeJS在处理从别的客户端或服务端收到的头字段时,都统一地转换为了小写字母格式,以便开发者能使用统一的方式来访问头字段,例如headers[‘content-length’]。 - 为什么http模块创建的HTTP服务器返回的响应是chunked传输方式的?
.writeHeader()写入响应头,.write 写入相应体, .end()方法结束响应
因为默认情况下,使用.writeHead方法写入响应头后,允许使用.write方法写入任意长度的响应体数据,并使用.end方法结束一个响应。由于响应体数据长度不确定,因此NodeJS自动在响应头里添加了Transfer-Encoding: chunked字段,并采用chunked传输方式。但是当响应体数据长度确定时,可使用.writeHead方法在响应头里加上Content-Length字段,这样做之后NodeJS就不会自动添加Transfer-Encoding字段和使用chunked传输方式。
异步IO
阻塞 IO 和 非阻塞 IO 的区别:(内核在进行IO 操作时都要通过文件描述符进行管理)
- 阻塞 IO 是需要完成整个数据获取的过程,会造成 时间和 cpu的浪费
- 非阻塞 IO 是不带数据直接返回,想要获取数据需要再次通过文件描述符进行读取;
- 非阻塞 IO 需要通过重复操作调用的技术(轮询)来判断是否进程已经结束,是否可以获得最终想要获得的数据
- 轮询技术 :1.read (不停地read 一直进行调用来判断)2.select (先进行 read ,然后select 进行获取数据 存在限制:采用1024 长度数组进行存储状态,所最多同时检查1024个文件描述符)3.pool (是在select 基础上进行改进,采用链表来进行存储,不过文件过多时,性能还是比较差) 4.epoll (Linux 下 采用休眠的方式进行轮询,在进入轮询的时候没有检查到IO 事件,将会休眠,直到事件发生将其唤醒,不会浪费cpu,效率高)
异步IO
有多种实现方式:
- windows 平台使用 IOCP进行实现异步IO (调用异步 IO方法,等待IO完成后的通知,执行回调,内部使用的是线程池
node 的实现异步 IO
1.事件循环(进程启动会创建一个事件循环,每一次的循环成为 Tick ,每次 Tick检查是否有事件待处理,有就去除事件及其相关的回调函数,如果存在相关联的回调,执行回调,然后进入下次 Tick ,如果没有事件处理,则退出进程。
2.观察者:对事件进行兼监听的,判断是否有事件进行处理
3.请求对象: JS调用 到内核 IO 操作完成的过渡过程中,会产生一个请求对象(包含请求的数据 req->result,和各种状态)
- 执行回调
非IO的异步API
- settimeout();
- setInterval();
- process.nextTick(); ->idle观察者,每次循环中都会执行完数组中的所有事件
- setImmediate() ->check观察者 每次只会执行链表上的一个事件
优先级:3>4 ,(每次轮询中idle观察者 > IO观察者 > check观察者
node.js 回调函数
将回调函数作为函数的参数,当这个函数执行完成之后执行回调函数
js 代码: fn2( fn1(“argument”) )
node.js 代码 : fn1(”argument”,fn2(argument){
//doing something
})