0%

Node.js-note

1.Node.js简介

  • Node.js是一个能够在服务器端运行的javaScript的开放源代码,跨平台javaScript运行环境

  • Node采用Google开发的V8引擎运行js代码,使用事件驱动、非阻塞和异步I/o模型等技术来提高性能,可以优化应用程序的传输和规模

  • Node大部分基本模块都用javaScript编写。在Node出现之前js通常作为客户端程序设计语言使用,以Js写出程序常在用户的浏览器上运行

  • 目前,Node已被IBM,Microsoft、Yahoo!、Wakmart、Groupon、SPA、LinkedIn、Rakuten等企业采用

2.Commonjs规范

2.1ECMAScript标准缺陷

  • 没有模块系统
  • 标准库较少
  • 没有标准接口
  • 缺乏管理系统

2.2模块化

  • 如果程序设计的规模化达到了一定程度,则必须对其进行模块化
  • 模块化可以有多种形式,单至少应该提供能够讲代码分割为多个源文件的机制
  • CommonJS的模块功能可以帮我们解决该问题

2.3CommonJS规范

  • CommonJs规范的提出,主要是为了弥补当前javascript没有标准的缺陷

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

  • CommonJS对模块的定义十分简单:

    • 模块引用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      module-1
      /*
      模块化
      优点:解耦 提高代码复用性
      - 在Node中,一个js就是一个模块
      - 在Node中,每一个js文件中的js代码都是独立运行在一个函数中
      而不是全局作用域,一个模块中的变量在其他模块中是无法使用和访问
      */

      console.log("我是module.js-02");
      let y = 2;

      /**
      * 我们通过export来向外部暴露变量和方法
      * 向外部暴露属性或者方法设置为exports的属性即可
      */
      exports.x = "我是module中的x变量";
      exports.y = y;
      exports.fn = function () {
      console.log("我是module的函数");
      };

      module-2
      /*
      引入其他模块
      在node中,通过require()函数来引入外部模块
      require()可以传递一个文件的路径作为参数,node将会自动根据该路径来引入外部模块
      这里路径,如果使用相对路径,必须以.或..开头

      使用require引入模块后会返回一对象,这个对象代表的是我们引入的模块
      */

      var module = require('./02.module');
      console.log(module);
      module.fn();
    • 模块定义

    • 模块标识

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

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

      模块分为两类
      核心模块

      由node引擎提供的模块

      核心模块的标识就是,模块的名字
      文件模块

      由用户自己创建的模块

      文件模块的标识就是文件的路径(绝对路径,相对路径)
      相对路径使用.或..开头

      tip:每一个模块都会被当作一个函数被node执行

      当node在执行模块中的代码时,它会首先在代码的最顶部,添加如下代码

      function (exports, require, module, filename, dirname) {

      }

      实际上模块中的代码都是包装在一个函数中执行,并在在函数执行的时候,同时包括5个实参

      exports

      该对象用于将变量或函数暴露到外部

      require

      函数,引入外部的模块

      module

      module代表当前模块本事

      我们既可以使用exports也可以使用module.exports

      __filename

      当前模块的绝对路径

      __dirname

      当前模块所在文件夹的绝对路径

3.包 package

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

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

  • 包结构

    用于组织包中的各种文件

  • 包描述文件

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

3.1包结构

包实际上就是一个压缩文件,解压以后还原为目录。符合规范的目录,应该包含如下文件:

  • package.json 描述文件类似于包的简历(必须)

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

    package.json字段

  • bin 可执行二进制文件

  • lib js代码

  • doc 文档

  • test 单元测试

4.NPM(Node Package Manager)

  • CommonJS包规范是理论,NPM是其中一种实践
  • 对于Node而言,NPM帮助其完成了第三方模块的发布,安装和依赖等。借助NPM。Node与第三方模块之间形成了很好的一个生态系统

4.1npm命令

  • npm -v 查看版本
  • npm 帮助说明
  • npm search 包名 搜索模块包
  • npm install/i 包名 在当前目录安装包(全局安卓一般都是安装一些与计算机打交道的工具)
  • npm install/i 包名 -g 全局模式安装包
  • npm remove/r 包名 删除包
  • npm init 初始化模块包
  • npm install 包名 —save 安装并添加到模块依赖中

5.缓冲区

  • 从结构上看Buffer非常像一个数组,它的元素为16进制的两位数
  • 实际上一个元素就标识内存中的一个字节。
  • 世界上Buffer中的内存不是通过javaScript分配的,而是底层的C++申请的。
  • 也就是我们可以直接通过Buffer来创建内存中的空间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
Buffer(缓冲区)
- Buffer的结构和数组很像,操作方法也和数组相似
- js数组中不能存储二进制文件,而Buffer就是专门用于存储二进制文件的数组
- 使用Buffer不需要引入模块,直接使用即可
- 在Buffer中存储的都是二进制数据,但是显示时都是以16进制的形式显示
Buffer中的每一个元素的大小是从00 -ff 0 -255
00000000 - 11111111
计算机中 一个0或一个1 我们称之为1位(bit)
8bit =1byte(字节)
1024bit = 1kb
1024kb = 1mb
1024mb = 1gb
1024gb = 1tb

- Buffer的大小一旦确定,则不能修改,Buffer实际上是对内存的直接操作
- Buffer.toString()直接将数据转换成字符串
*/

var str = "Hello 尚硅谷";

// 将字符串保存到Buffer中
// var buffer1 = Buffer.from(str);
// // 一个中文占用3个字节
// console.log(buffer1.length); // 占用内存大小
// console.log(str.length); // 字符串的长度
// console.log(buffer1);

// 创建一个指定大小的Buffer
// Buffer构造函数是不推荐使用的
// var buffer = Buffer.alloc(10);
// // 通过索引,来操作buf中元素
// buffer[0] = 88;
// buffer[1] = 255;
// buffer[2] = 0xaa;

// 只要数组在控制台或者页面输出一定都是100进制
// console.log(buffer[2].toString(16));
// console.log(buffer.length);
//
// for (var i = 0; i < buffer.length; i++) {
// console.log(buffer[i]);
// }

// Buffer.allocUnsafe(size)创建指定大小的Buffer,但是buffer中可能含有敏感数据
// var buffer = Buffer.allocUnsafe(10);
// console.log(buffer);


var buffer = Buffer.from("我是一段文本数据");

console.log(buffer.toString());

6.FS(文件系统)

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

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

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

  • 要使用fs模块,首先需要对其进行加载

    1
    const fs = require("fs");

6.1同步和异步调用

  • fs模块中所有的操作都有两种形式可供选择同步异步
  • 同步文件系统会阻塞程序的执行,也就是除非操作完毕,否则不会向下执行代码
  • 异步文件系统不会阻塞程序的执行,而是在操作完成时,通过回调函数将结果返回

6.2同步写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
文件系统(File System)
- 文件系统简单来说就是通过Node来操作系统中的文件
- 使用文件系统,需要引入fs模块,fs是核心模块,直接引入不需要下载
同步文件写入
文件写入
- 手动操作步骤
1.打开文件
fs.openSync(path,flags[,mode])
- path 要打开的文件路径
- flags 打开文件要做的操作类型
r 只读的
w 可写的
- mode 设置文件操作权限,一般不传
- 该方法会返回一个文件的描述作为结果,我们可以通过描述符来对文件进行各种操作
2.向文件写入数据
fs.writeSync(fd, string[, position[, encoding]])
- fd 文件描述,需要传递要写入的文件描述符
- string 要写入的内容
- position 写入起始位置(一般不传)
- encoding 写入编码(一般不传)

3.保存并关闭文件

*/
var fs = require("fs");
var fd = fs.openSync("hello.txt", "w");
// 向文件中写入内容
fs.writeSync(fd,"今天的天气真不错~~~~");
// console.log(fd);

// 关闭文件
fs.closeSync(fd);

6.3异步写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
异步文件写入
fs.open(path[, flags[, mode]], callback)
- 用于打开一个文件
- 异步调用的方法,结果都是通过回调函数返回
- 回调函数两个参数:
err 错误对象,如果没有错误则为null
fd 文件描述符
*/

// 引入fs模块
var fs = require('fs');
// 打开文件
fs.open("hello2.txt", "w", function (err, fd) {
// 判断是否出错
if (!err) {
console.log(fd);
// 如果没有错误直接执行写入操作
fs.write(fd, "我是异步写入的内容~~~", function (err) {
if (!err) {
console.log("写入成功")
}
// 关闭文件
fs.close(fd, function (err) {
if (!err) {
console.log("fs操作关闭");
}
})
})
} else {
console.log(err);
}
});

6.4简单文件写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
fs.writeFile(file, data[, options], callback) 异步
fs.writeFileSync(file, data[, options]) 同步
- file 要操作的文件路径
- data 要写入的数据
- options 选项可以对写入进行一些设置
- callback 写入完成以后执行的函数
*/

// 引入fs模块
var fs = require('fs');

fs.writeFile("hello3.txt", "这是writeFile写入的内容",{flag:"w"}, function (err) {
if (!err) {
console.log("写入成功");
}else {
console.log(err);
}
});

6.5流式文件写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
同步、异步、简单文件写入都不合适大文件的写入,性能较差,容易导致内存溢出
*/
var fs = require('fs');

// 流式文件写入
// 创建一个可写流
/**
* fs.createWriteStream(path[, options])
* - 可以用来创建一个可写流
* - path,文件路径
* - options 配置的参数
*/

var ws = fs.createWriteStream('hello3.txt');

// 可以通过监听流的open和close事件来监听的打开和关闭
/**
* on(事件字符串,回调函数) 可以为对象绑定一个事件
* once(事件字符串,回调函数 可以为我们的对象绑定一个一次性的事件,该事件将会触发一次之后自动失效
*
*/
ws.once("open", function () {
console.log("流打开了");
});
ws.once("close", function () {
console.log("流关闭了");
});
//通过ws向文件中输出内容
ws.write('窗前明月光\n');
ws.write('疑是地上霜\n');
ws.write('举头望明月\n');
ws.write('低头思故乡\n');

// 关闭流
ws.end();

6.6简单文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
1.同步文件读取
2.异步文件读取
3.简单文件读取
fs.readFile(path[, options], callback)
fs.readFileSync(path[, options])
- path文件路径
- options 读取选项
- callback回调函数,通过回调函数将读取的内容返回(err,data)
err 错误对象
data 读取到的数据,返回buffer对象
4.流式文件读取
*/

var fs = require('fs');
fs.readFile('hello3.txt', function (err, data) {
if (!err) {
console.log(data.toString());
// 将我们读到内容写入到其他文件中
fs.writeFile('hello4.txt',data,function (err) {
if (!err) {
console.log('输出成功');
}
})
}
});

6.8流式文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
流式文件读取适用于一些比较大的文件,可以分多次文件读取内存中
*/

var fs = require('fs');

//创建一个可读流
var rs = fs.createReadStream('code.png');
//创建一个可写流
var ws = fs.createWriteStream("a.png");
//监听流的开启和关闭
rs.once("open", () => {
console.log("可读流被打开了");
});

rs.once("close", () => {
console.log("可读流被关闭");
});

ws.once("open", () => {
console.log("可写流被打开了");
});

ws.once("close", () => {
console.log("可写流被关闭");
ws.end();
});
//如果要读取一个可读流中的数据,必须要为可读流绑定一个data事件,data事件绑定完毕,它会自动开始读取数据
rs.on("data", (data) => {
// console.log(data.length);
// 将读取到的数据写入可写流中
ws.write(data);
});

简化方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
流式文件读取适用于一些比较大的文件,可以分多次文件读取内存中
*/

var fs = require('fs');

//创建一个可读流
var rs = fs.createReadStream('code.png');
//创建一个可写流
var ws = fs.createWriteStream("b.png");
//监听流的开启和关闭

//pipe()可以将我们可读流中的内容,直接输出到可写流中
rs.pipe(ws);

6.9fs其他操作

  • 验证路径是否存在

    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[,filename[,options],listener)

谢谢老板