Node.js应用

185 阅读9分钟

「本文正在参与技术专题征文Node.js进阶之路,点击查看详情」 

Node的历史

2009年 瑞安·达尔(Ryan Dahl)在GitHub上发布node的最初版本 

2010年1月 Node的包管理器npm诞生 

2010年底 Joyent公司赞助Node的开发,瑞安·达尔加入旗下,全职负责Node 

2011年7月 Node在微软的帮助下发布了windows版本 

2011年11月 Node超越Ruby on Rails,称为GitHub上关注度最高的项目 

2012年1月 瑞安·达尔离开Node项目 

2014年12月 Fedor Indutny在

2014年12月制作了分支版本,并起名“io.js” 

2015年初 Node.js基金会成立(IBM、Intel、微软、Joyent) 

2015年9月 Node.js和io.js合并,Node 4.0发布 

2016年 Node 6.0发布 

2017年 Node 8.0发布 

Node的用途

• Web服务API,比如REST 

• 实时多人游戏 

• 后端的Web服务,例如跨域、服务器端的请求 

• 基于Web的应用 

• 多客户端的通信,如即时通信 安装NODE.JS 万事开头难 

COMMONJS规范

ECMAScript标准的缺陷 

• 没有模块系统 

• 标准库较少

 • 没有标准接口

 • 缺乏管理系统 

模块化

 • 如果程序设计的规模达到了一定程度,则 必须对其进行模块化。 

• 模块化可以有多种形式,但至少应该提供 能够将代码分割为多个源文件的机制。 

• CommonJS 的模块功能可以帮我们解决该 问题。 

CommonJS规范 

• CommonJS规范的提出,主要是为了弥补当 前JavaScript没有模块化标准的缺陷。 

• CommonJS规范为JS指定了一个美好的愿景, 希望JS能够在任何地方运行。 

• CommonJS对模块的定义十分简单: – 模块引用 – 模块定义 – 模块标识 

模块引用

• 在规范中,定义了require()方法,这个方 法接手模块标识,以此将一个模块引入到 当前运行环境中。

• 模块引用的示例代码: – var math = require('math'); 

模块定义

• 在运行环境中,提供了exports对象用于导 出当前模块的方法或者变量,并且它是唯 一的导出的出口。 

• 在模块中还存在一个module对象,它代表 模块自身,而exports是module的属性。 

• 在Node中一个文件就是一个模块。 模块定义 exports.xxx = function() {}; module.exports = {}; 

模块标识

• 模块标识其实就是模块的名字,也就是传 递给require()方法的参数,它必须是符合 驼峰命名法的字符串,或者是以.、..开头的 相对路径、或者绝对路径。 

• 模块的定义十分简单,接口也十分简洁。 每个模块具有独立的空间,它们互不干扰, 在引用时也显得干净利落。 

Node的模块实现

• Node中虽然使用的是CommonJS规范,但是 其自身也对规范做了一些取舍。 

• 在Node中引入模块,需要经历如下3个步骤: – 路径分析 – 文件定位 – 编译执行 

• 在Node中,模块分为三类:一类是底层由 C++编写的内建模块,一类是Node提供的核 心模块;还有一类是用户编写的模块,称为文 件模块。 

包 package

• CommonJS的包规范允许我们将一组相关 的模块组合到一起,形成一组完整的工具。 

• CommonJS的包规范由包结构和包描述文 件两个部分组成。 

• 包结构 – 用于组织包中的各种文件 

• 包描述文件 – 描述包的相关信息,以供外部读取分析 

包结构

• 包实际上就是一个压缩文件,解压以后还 原为目录。符合规范的目录,应该包含如 下文件: – package.json 描述文件 – bin 可执行二进制文件 – lib js代码 – doc 文档 – test 单元测试 

包描述文件

• 包描述文件用于表达非代码相关的信息, 它是一个JSON格式的文件 – package.json, 位于包的根目录下,是包的重要组成部分。

 • package.json中的字段 

– name、description、version、keywords、 maintainers、contributors、bugs、 licenses、repositories、dependencies、 homepage、os、cpu、engine、builtin、 directories、implements、scripts、author、 bin、main、devDependencies。 

NPM(Node Package Manager)

• CommonJS包规范是理论,NPM是其中一 种实践。 

• 对于Node而言,NPM帮助其完成了第三 方模块的发布、安装和依赖等。借助NPM, Node与第三方模块之间形成了很好的一个 生态系统。 

NPM命令

• npm –v – 查看版本 

• npm – 帮助说明 

• npm search 包名 – 搜索模块包 

• npm install 包名 – 在当前目录安装包 

• npm install 包名 –g – 全局模式安装包

NPM命令

 • npm remove 包名 – 删除一个模块 

• npm install 文件路径 – 从本地安装 

• npm install 包名 –registry=地址 – 从镜像源安装 

• npm config set registry 地址 – 设置镜像源 

Buffer(缓冲区)

• 从结构上看Buffer非常像一个数组,它的元 素为16进制的两位数。 

• 实际上一个元素就表示内存中的一个字节。 

• 实际上Buffer中的内存不是通过JavaScript 分配的,而是在底层通过C++申请的。 

• 也就是我们可以直接通过Buffer来创建内存 中的空间。 

Buffer的操作

• 使用Buffer保存字符串 

• 创建指定大小的Buffer对象 let str = "你好 atguigu"; let buf = Buffer.from(str , "utf-8"); let buf3 = Buffer.alloc(1024*8) 

Buffer的转换

• Buffer与字符串间的转换 

– 支持的编码: 

• ASCII、UTF-8、UTF-16LE/UCS-2、Base64、 Binary、Hex

 – 字符串转Buffer 

• Buffer.from(str , [encoding]); 

– Buffer转字符串 

• buf.toString([encoding] , [start] , [end]); 

写入操作

• 向缓冲区中写入字符串 – buf.write(string[, offset[, length]][, encoding]) 

• 替换指定索引位置的数据 – buf[index] 

• 将指定值填入到缓冲区的指定位置 – buf.fill(value[, offset[, end]][, encoding])

读取操作

• 将缓冲区中的内容,转换为一个字符串返回 – buf.toString([encoding[, start[, end]]]) 

• 读取缓冲区指定索引的内容 – buf[index] 

其他操作

• 复制缓冲区 – buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]]) 

• 对缓冲区切片 – buf.slice([start[, end]]) 

• 拼接缓冲区 – Buffer.concat(list[, totalLength]) 

fs(文件系统)

• 在Node中,与文件系统的交互是非常重要 的,服务器的本质就将本地的文件发送给 远程的客户端 

• Node通过fs模块来和文件系统进行交互 

• 该模块提供了一些标准文件访问API来打开、 读取、写入文件,以及与其交互。 

• 要使用fs模块,首先需要对其进行加载 – const fs = require("fs"); 

同步和异步调用

• fs模块中所有的操作都有两种形式可供选择 同步和异步。 

• 同步文件系统会阻塞程序的执行,也就是 除非操作完毕,否则不会向下执行代码。 

• 异步文件系统不会阻塞程序的执行,而是 在操作完成时,通过回调函数将结果返回。 

打开和关闭文件

• 打开文件 

– fs.open(path, flags[, mode], callback) 

– fs.openSync(path, flags[, mode]) 

• 关闭文件

– fs.close(fd, callback) 

– fs.closeSync(fd) 

打开状态

写入文件

• fs中提供了四种不同的方式将数据写入文件 

– 简单文件写入 

– 同步文件写入 

– 异步文件写入 

– 流式文件写入 

简单文件写入

• fs.writeFile(file, data[, options], callback) 

• fs.writeFileSync(file, data[, options]) 

• 参数: 

– file 文件路径 

– data 被写入的内容,可以是String或Buffer 

– options 对象,包含属性(encoding、mode、 flag) 

– callback 回调函数 

同步文件写入 

• fs.writeSync(fd, buffer, offset, length[, position]) 

• fs.writeSync(fd, data[, position[, encoding]]) 

• 要完成同步写入文件,先需要通过openSync()打开文件来获取 一个文件描述符,然后在通过writeSync()写入文件。 

• 参数 

– fd 文件描述符,通过openSync()获取 

– data 要写入的数据(String 或 Buffer) 

– offset buffer写入的偏移量

– length 写入的长度 

– position 写入的起始位置 

– encoding 写入编码 

异步文件写入 

• fs.write(fd, buffer, offset, length[, position], callback) 

• fs.write(fd, data[, position[, encoding]], callback) 

• 要使用异步写入文件,先需要通过open()打开文件,然后在回 调函数中通过write()写入。 

• 参数: 

– fd 文件描述符 

– data 要写入的数据(String 或 Buffer)

– offset buffer写入的偏移量 – length 写入的长度 

– position 写入的起始位置 – encoding 写入编码 

流式文件写入

• 往一个文件中写入大量数据时,最好的方法之一 是使用流。 

• 若要将数据异步传送到文件,首需要使用以下语 法创建一个Writable对象:

 – fs.createWriteStream(path[, options]) 

• path 文件路径 

• options {encoding:"",mode:"",flag:""} 

• 一旦你打开了Writable文件流,就可以使用 write()方法来写入它,写入完成后,在调用end() 方法来关闭流。 

读取文件

• fs中提供了四种读取文件的方式 

– 简单文件读取 

– 同步文件读取 

– 异步文件读取

 – 流式文件读取 

简单文件读取

• fs.readFile(file[, options], callback) 

• fs.readFileSync(file[, options]) 

– 参数: 

• file 文件路径或文件描述符 

• options | – encoding | 默认 = null – flag 默认 = 'r' 

• callback 回调函数,有两个参数err 、data 

同步文件读取

• fs.readSync(fd, buffer, offset, length, position) – 参数: 

• fd 文件描述符 

• buffer 读取文件的缓冲区 

• offset buffer的开始写入的位置 

• length 要读取的字节数 

• position 开始读取文件的位置 异步文件读取 

• fs.read(fd, buffer, offset, length, position, callback) 

– 参数: 

• fd 文件描述符 

• buffer 读取文件的缓冲区 

• offset buffer的开始写入的位置 

• length 要读取的字节数 

• position 开始读取文件的位置 

• callback 回调函数 参数err , bytesRead , buffer 

流式文件读取 

• 从一个文件中读取大量的数据时,最好的方法之一就是 流式读取,这样将把一个文件作为Readable流的形式 打开。 

• 要从异步从文件传输数据,首先需要通过以下语法创建 一个Readable流对象: 

– fs.createReadStream(path[, options]) 

• path 文件路径 

• options {encoding:"",mode:"",flag:""} 

• 当你打开Readable文件流以后,可以通过readable事 件和read()请求,或通过data事件处理程序轻松地从它 读出。 

其他操作

• 验证路径是否存在 – fs.exists(path,callback) – fs.existsSync(path) 

• 获取文件信息 – fs.stat(path, callback) – fs.statSync(path) 

• 删除文件 – fs.unlink(path, callback) – fs.unlinkSync(path) 其他操作 

• 列出文件 – fs.readdir(path[, options], callback) – fs.readdirSync(path[, options]) 

• 截断文件 – fs.truncate(path, len, callback) – fs.truncateSync(path, len) 

• 建立目录 – fs.mkdir(path[, mode], callback) – fs.mkdirSync(path[, mode]) 其他操作 

• 删除目录 – fs.rmdir(path, callback) – fs.rmdirSync(path) 

• 重命名文件和目录 – fs.rename(oldPath, newPath, callback) – fs.renameSync(oldPath, newPath) 

• 监视文件更改写入 – fs.watchFile(filename[, options], listener)