回到node
- node特性
- 基于chrome V8特性
- 基于事件驱动
- 非阻塞io
- node的web开发优势
- 高并发服务
- 高性能io node内部有一个进程池
- 前后端代码统一
node内部架构
- 通过绑定调用C++,js可以调用c++程序。js是单线程的,如何去调用底层呢 node有一个插件比如libuv用来读取文件。node底层c++有一个线程池,这个跟js无关。还有事件循环,有一个循环机制维护一个消息队列
node模块机制
- 以模块(文件)来划分功能、组织代码和代码复用
- 用包规范来管理应用和可复用组件
- 用npm工具和网站进行开源社区代码共享
Node模块模型
- 核心模块(C++写的,可以直接拿来用的)
- C/C++内建模块,最底层的模块。提供API给Javascript核心模块或其他Javascript文件模块调用(process.binding())
- Javascript核心模块,存放在node安装目录的lib下,为C/C++内建模块提供封装和桥接
- 文件模块
- C++扩展模块,为了运行效率和特殊目的按照Node规范编译,扩展名为node,用process.dlopen()加载执行(动态连结库)
- Javascript文件模块,由第三方或用户自行编写的模块
常用的Node核心模块
- console:控制台输入输出
- fs:与文件系统交互(在不同操作系统下是不一样的,node底层有个机制封装,可以使我们用的一样,实现跨平台)
- fttp:提供HTTP服务器功能
- net:有很多C++的库 提供TCP/IP网络功能
- os:提供了一些操作系统相关的实用方法,比如取cpu、内存的信息
- path:一般和os合起来用 提供了一些操作系统相关的实用方法
- url:解析URL
- querystring:解析URL的查询字符串
- crypto:提供加密和解密功能,基本上是对OpenSSL的包装
模块对象
- 模块对象(module)实际上也是一个文件,表示当前模块文件,是一个js对象。模块对象不是全局的,而是每个模块唯一的
- 模块对象的属性
- module.id,模块的标识符,通常是完全解析后的文件名
- module.loaded 模块是否已经加载完成,或正在加载中 js运行时要先运行模块中的代码,加载完成后再执行其他的
- filename 模块完全解析后的文件名
- parent 调用该模块的模块
- children 被该模块引用的模块对象
- exports 模块的导出对象,默认为空对象
模块的导出
- module.exports,模块的导出对象,默认为空对象 例子 exptest
- exports变量是module.exports的快捷方式,module.exports.f=…可以被更简洁地写成 exports.f=…
- exports变量直接赋值(exports=…)会使之不再是module.exports的快捷方式,导致不能被导出
- 为避免出错,模块的导出都用module.exports,不用exports
模块引用
- 使用require方法来指定加载模块,方法的参数是模块的标识符
- 模块标识符包括
- 核心模块,如http, fs, path等(核心模块不需要写路径,默认路径)
- 文件模块,可以省略文件扩展名
- 以.或..开始的相对路径
- 绝对路径
- 安装包模块,如express, colors
- 在全局(npm list -global)或当前应用的node_modules中寻找目录
- 在package.json文件中,寻找main属性所指明的模块入口文件
- 没有package.json文件,以index.js为模块入口文件
- require.resolve()可用来解析模块标识符的绝对路径。
模块缓存
- 模块在第一次require后会被缓存,多次require不会导致模块的代码被执行多次
- Node模块的缓存不同于浏览器的js缓存,浏览器只缓存文件,Node模块缓存的是编译和执行之后的对象
- require.cache对象代表Node模块缓存区,缓存的模块以属性的方式加入该对象,可以用require.cache[‘模块标识符’]来访问具体的缓存模块,也可以delete该缓存
node包规范
- Node采用包来对一组具有相互依赖关系的模块进行统一管理,封装为独立的复用组件或单个应用
- Node的包通常为一个目录,包括如下内容
- package.json,包的描述文件
- bin目录,用于存放可执行文件和其他二进制文件
- lib目录,用于存放待加载的js文件
- doc目录,用于存放包使用说明的文档
- test目录,用于存放单元测试用例代码文件
- node_modules目录,本地安装的其他第三方包(全局安装的第三方包用npm list -g查询)
package.json
- package.json文件是一个JSON对象
- package.json的主要属性
- name:包名,npm install依赖此名称
- version:版本号,版本号为a,b,c的形式,其中a是大版本号,b是小版本号,c是补丁号
- description:项目描述,npm search会用到
- keywords:关键字,npm search会用到
- main:包输出主入口模块的ID,当包被require时,返回的就是这个模块的导出
- author,contributors:author是一个人,contributors是一组人
- dependents:当前包所依赖的其他包和包的版本
- scripts:指定了运行脚本命令的npm命令行缩写
基于包规范开发应用流程
- 创建目录
- 进入目录
- 初始化(npm init生成package.json文件)
- 配置依赖项(修改package.json的dependencies)
- 安装依赖包(npm install)
- 配置运行脚本命令(scripts的start子项,配置start是为统一包运行入口方式)
- 编写代码
- 运行代码(npm start)
非阻塞IO和事件驱动
非阻塞IO
- 操作系统内核进行I/O操作时有两种方式
- 阻塞,应用要读取磁盘某文件时,要等待系统内核完成硬盘寻道、读取数据、复刻数据到内存等操作后,调用才结束
- 非阻塞,应用的I/O调用可以立即返回,但返回的是调用的状态,需要轮询的方式确定系统内核是否完成所有操作
- Windows的IOCP及*nix的libev有不同的实现
- Node的非阻塞I/O
- 底层是基于libuv的线程池(但也把IOCP包括在内(为了跨平台))