学习Node过程中需要了解的一些相关基础概念, 包括文件处理, 网络相关概念, 以及npm的一些知识点.

文件处理

二进制数据

Binary Data: 以二进制形式存储的数据(通常是数字, 由0和1组成), 每个1或0是1bit(1 binary digit).

二进制与十进制数据:

base2-10

字符集

字符集(Character Set): 以数字的形式表示字符, 每个字符用一组不同的数字集合来表示. 常见的字符集有Unicode, ASCII.

Unicode示例:

h-104
e-101
l-108
l-108
o-111

字符编码

字符编码(Character Encoding): 以二进制的形式存储字符, 最常见的字符编码是UTF-8.

char-encoding

在处理服务器端数据时, 需要处理二进制数据, 字符集以及进行字符编码. JavaScript可以处理字符集和数字之间的转化, 但是无法对字符编码以及二进制数据进行处理. 因此Node扩展了处理二进制数据以及字符编码的功能.

Buffer

Buffer是暂时存取需要转移的数据的区域, 存储容量有限制. (a temporary holding spot for data being moved from one place to another[Intentionally limited in size]).

buffer

Node中的Buffer对象内置了许多方法用以处理二进制数据, Buffer内存储的数据形式默认是二进制.

1
2
3
4
5
6
7
8
9
10
11
var buf = new Buffer('Hello','utf8');
console.log(buf); // <Buffer 48 65 6c 6c 6f>
// 数据以16进制的形式显示, 但实际是以二进制的形式存储
console.log(buf.toString()); // Hello
console.log(buf.toJSON()); // { type: 'Buffer', data: [ 72, 101, 108, 108, 111 ] }
console.log(buf[2]); // 108

buf.write('wo');
console.log(buf.toString()); // wollo
buf.write('wowoworld');
console.log(buf.toString()); // wowow

Buffer是有限的数据集合, 上例中的buf被初始化为存储5个字符, 存储的容量不能被改变, 最多只能占用初始化时的那些内存空间.

ES6 Typed Arrays

原来JavaScript无法处理二进制数据, 但ES6中引入了处理的机制. 不过在Node中依然是libuv处理二进制数据.

1
2
3
4
5
6
7
8
9
var buffer = new ArrayBuffer(8); // 创建一个字节长度为8(8bytes)的Buffer

var view = new Int32Array(buffer); // 每个整型数字占用32bits空间, view是类型数组, 在这里只可以存储两个元素, 因为buffer的存储空间只有64bits.

view[0] = 5;
view[1] = 15;

console.log(view);
console.log(buffer);

fs.readFile

1
2
3
4
5
6
7
8
9
10
11
12
13
var fs = require('fs')

var greet = fs.readFileSync(__dirname + '/greet.txt');
// 同步读取文件: 直到buffer被填满, 再进行下一步操作
// 配置文件使用同步读取, 对于较大的文件使用异步读取速度更快
console.log(greet);

var greet2 = fs.readFile(__dirname + '/greet.txt', 'utf8',
function(err, data){
console.log('Async: ' + data);
});

console.log('Done!');

Error-First Callback: Node中的回调函数大多将error对象作为第一个参数

读取文件时, 会首先将文件内容转换为二进制数据存入buffer再进行处理, 但使用buffer有个问题,如果一下子处理过多的buffer, 会占用太多的内存空间, 耗费较多时间, 为了解决这个问题, 引入了stream的概念.

Stream

Stream: A sequence of data made available over time. Pieces of data that eventually combine into a whole. 直播的英文是Live-Streaming, 利用stream分段传输影片内容.

Chunk: A piece of data being sent through a stream. Data is split in ‘chunks’ and streamed.

stream

buffer和stream

buffer-stream

stream继承自EventEmitter. stream是抽象的父类(Abstract[Base] Class),不直接操作stream函数构造器, 操作继承自stream的对象(Custom Stream).

stream-inherits

有多种类型的stream:

  1. Writable Stream
  2. Readable Stream
  3. Duplex Stream
  4. Transform Stream

Duplex Stream与Transform Stream的区别

可读(readable)和可写(writable)都是对于Node来说的, 比如浏览器与服务器之间的request和response, request对于Node是可读的, response是可写的.

stream-node

fs.createReadStream

ReadStream继承自Readable, Readable继承自Stream, Stream继承自EventEmitter

1
2
3
4
5
6
7
8
9
10
var fs = require('fs');

var readable = fs.createReadStream(__dirname + '/greet.txt', {encoding:'utf8', highWaterMark: 32 * 1024});

var writable = fs.createWriteStream(__dirname + '/greetcopy.txt');

readable.on('data', function(chunk){
console.log(chunk.length);
writable.write(chunk);
});

读取文件, 然后把文件内容填充入buffer, 如果文件内容小于buffer的存储容量, 会输出所有数据至一个buffer, 如果超过一个buffer的容量, 会分成多个buffer输出. 默认一个buffer容量为64kb, highWaterMark: 32 * 1024将一个buffer的容量设置为32kb.

Pipe

Pipe: 连接两个stream, 一个可读stream和一个可写stream. Connecting two streams by writing to one stream what is being read from another. In Node you pipe from a Readable stream to a Writable stream.

pipe方法在所有readable stream的prototype上.

pipe

1
2
3
4
5
6
7
8
9
var fs = require('fs');

var readable = fs.createReadStream(__dirname + '/greet.txt');
var writable = fs.createWriteStream(__dirname + '/greetcopy.txt');

// readable.on('data', function(chunk){
// writable.write(chunk);
// });
readable.pipe(writable);

pipes can be chained:

pipe-chain

Method Chaining: a method returns an object so we can keep calling more methods. (Sometimes it returns the parent object(called ‘cascading’) and sometimes some other object.)

1
2
3
4
5
6
7
8
var fs = require('fs');
var zlib = require('zlib'); // 创建gzip文件的模块, 功能是压缩文件

var readable = fs.createReadStream(__dirname + '/greet.txt');
var compressed = fs.createWriteStream(__dirname + '/greet.txt.gz');
var gzip = zlib.createGzip(); // 创建transform stream(既可读又可写), 接收文件中的chunk, 将其压缩.

readable.pipe(gzip).pipe(compressed);

处理文件和数据时应首先想到使用stream和异步操作, 有利于性能提升.

网络

TCP/IP

client-server-model

客户端发出的请求和服务器作出的响应数据本身需要遵循某种标准(HTTP, FTP, SMTP), 它们之间的信息传输方式也需要遵循某种标准(TCP[Transmission Control Protocol]).客户端和服务器之间传递信息时, 需要知道信息传输的具体目的地, IP(Internet Protocol)就是双方识别的依据. 当客户端和服务器成功识别, 操作系统会开启网络套接字(socket), 以完成信息的传输.

TCP-IP

socket

每一对客户端和服务器之间建立一个网络连接需要2个socket(client socket & server socket).
Client Socket的组成是IP地址加端口号(Port), 端口号的数值不固定, 由操作系统随机生成.
Server Socket的组成是域名加端口号(80), 80是所有网络传输的标准端口号.

在网络中, socket不断开启关闭. 当发出一个请求时, socket开启一段时间后关闭. 在某些情况下, socket是一直处于开启状态的, 比如在编辑Google Doc时, 因为文档内容需要和云端同步, 所以此时socket不可以关闭.

port

当计算机接收packet时, 可以通过端口(port)知道packet应该传输到哪一个程序.
When a program is setup on the operating to receive packets from a particular port, it is said that the program is ‘listening’ to that port.

socket-port

HTTP

HTTP(Hypertext Transfer Protocol): 在网络服务器和客户端之间传输的数据需要遵循的规则(格式).

http

MIME type: MIME(Multipurpose Internet Mail Extensions): 互联网媒体类型. A standard for specifying the type of data being sent.

原来是用于标识邮件的附件文件类型, 因此得名. 后来HTTP也使用这个标准.

例子: application/json, text/html, image/jpeg

Serialize

将对象转换成其他可以被传输, 存储的格式. 常见的格式有JSON, CSV, XML.

Routing

根据http请求分配在页面上显示的内容(Mapping http request to content).

http请求不直接请求文件, 而是向服务器发送请求, 服务器根据请求内容执行不同的操作:

  • 向客户端发送已存储在服务器中的文件
  • 从数据库获取数据并发送
  • 实时创建HTML文件

npm

包管理系统

包管理系统(package management system): 自动安装, 更新应用, 管理应用版本及依赖.

版本语义化

semantic versioning

MAJOR.MINOR.PATCH(1.8.2)

  • MAJOR: 比较大的变化, 代码有可能无法运行.
  • MINOR: 添加一些新特性, 代码依旧运行.
  • PATCH: 修复一些bug, 代码依旧运行.

package.json中管理版本依赖:

1
2
3
"dependencies": {
"moment": "^2.18.0"
}

“^2.10.6”: ‘^’允许minor和patch的更新.
“~2.10.6”: ‘~’只允许patch的更新.


参考