Node.js 学习笔记

简介

Node.js是一个服务端JS运行环境

单线程

CommonJS

缺陷:

  • 没有模块化

  • 标准库较少

  • 没有借口标准

  • 缺乏管理系统

NodeJS中, 一个js文件就是一个模块

引入别的模块

通过require()引入模块

如果是相对路径, 一点得以.或者..开头

1
require("./02.module.js");

使用require()引入模块后, 该函数返回一个模块, 这个对象代表的事引入的模块

1
var md = require("./02.module.js");

在node中, 每个js文件中的代码, 都是独立运行在一个函数中

不是全局作用域, 所以一个模块的变量和函数在其他模块无法访问

exports

可以通过exports 来向外部暴露变量和方法

1
exports.x = "我是exports x";

module.exports 可以通过赋值的方式暴露变量, exports不行

1
2
3
module.exports = {
...
}

模块分成两大类

  • 核心模块
    • node引擎提供的模块
    • 核心模块的标识, 就是模块的名字
  • 文件模块
    • 用户自己创建的模块
    • 文件模块的标识, 是文件袋路径

在全局中创建的变量函数都会作为global的属性属性或者方法保存

1
2
a = 10;
console.log(global.a)

当node执行模块中的模块时, 会在代码最顶部添加一行代码

1
2
3
function(exports,require, module, _filename, _dirname){

}
  • exports

    • 将变量暴露到外部
  • require

    • 引入外部模块
  • module

    • 模块本身
    • exports就是module的属性
  • __filename

    • 文件绝对路径
  • __dirname

    • 文件夹路径

package

包, 实际上是一个压缩文件, 解压后为原目录.

由包结构和包描述文件组成

符合规范的目录包含以下文件:

  • package.json — 必须的描述文件
  • bin - 可执行的二进制文件
  • lib - js代码
  • doc - 文档
  • test - 单元测试

WebStrom自动生成的文件package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"name": "nodejs-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

包描述文件用于表达非代码相关的信息, 是一个JSON文件

不可以在里面写注释

NPM

Node Package Manager

NPM帮助Node完成了第三方模块的发布安装和依赖

npm search 搜索

1
npm search math

npm init

可以创建一个package.json

npm install

1
npm install math

npm其他命令

  • npm -v
  • npm version
  • npm remove/r 包名
  • npm install 包名–save 安装包并添加依赖
  • npm install 不加包名, 下载当前项目依赖的包
  • npm install 包名 -g 全局安装包 (全局安装包一般都是一些工具)

淘宝npm镜像

淘宝npm

1
npm install -g cnpm --registry=https://registry.npm.taobao.org

Buffer

  • 结构和数组很像, 操作的方法也和数组类似

  • 专门用来存二进制数据

  • 不需要引入模块, 可以直接使用

  • 每个数据都是二进制, 但是显示的时候都是十六进制

  • buffer中一个元素, 占用一个字节Byte – 8bit

  • buffer 大小, 一但确定不再修改

    • 因为buffer实际上是对底层内存的直接操作
1
2
3
4
var str = "Hello";
Buffer.from(str);
console.log(buf.length); //占用的内存大小
console.log(str.length); //字符串的长度

创建指定大小的buffer

buffer所有构造函数都不推荐使用

1
var buf2 = new Buffer(10); //10个字节的buffer

通过索引操作buffer中的元素

1
2
3
var buf2 = Buffer.alloc(10);//10个字节的buffer
buf2[0] = 88;

File System

fs模块

1
var fs = require("fs");

同步和异步调用

  • 同步会阻塞程序运行
  • 异步不会阻塞程序运行

同步文件写入

1
var file = fs.openSync(path, flags[, mode])
  • path 要打开的文件路径
  • flags 要做的操作运行
    • 读写, 只读, 只写
    • r , w
  • mode 设置文件操作权限, 一般不传

方法返回一个文件描述符作为结果, 可以通过描述符文件对文件进行各种操作

1
fs.write(fd, string[, position[, encoding]])
  • fd 文件描述符, 需要传递要写入文件的描述符
  • string 需要写入的内容
1
fs.closeSync(fd)

关闭文件

异步写入文件

1
2
3
4
fs.open("hello.txt","w",function(){

console.log(arguments);
});

没有返回值, 但是有回调函数

  • 结果都是通过回调函数的参数返回, 参数有:
    • err 错误
    • fd 文件描述符

异步写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fs.open("hello.txt","w",function(err, fd){

if(!err){
fs.write(fd, "写入的内容", function(){
console.log("写入成功");
});
}
//关闭文件
fs.close(fd, function(err){
if(!err){
console.log("文件已经关闭");
}

});

});

简单的文件写入

1
fs.writeFile(file, date[, options], callback)
  • file 文件名
  • data
  • opions
  • callback 回调函数
1
2
3
4
5
6
var fs = require("fs");
fs.writeFile("hello.txt", "something", function(err){
if(!err){
console.log("success");
}
});

默认情况下, 覆盖原文件内容

追加内容到flags

  • a 打开文件用于追加, 没有则创建
1
2
3
4
5
fs.writeFile("hello.txt", "something",{flag:"a"}, function(err){
if(!err){
console.log("success");
}
});

流式文件写入

普通写入不适合大文件写入, 性能较差, 容易导致内存溢出

创建一个可写流

1
fs.createWriteStream(path[, options])
  • path 文件路径
  • options 配置都参数
1
var ws = fs.createWriteStream("hello4.txt");
1
2
3
4
5
ws.wirte("wirte something");
ws.wirte("wirte something");
ws.wirte("wirte something");
ws.wirte("wirte something");
ws.wirte("wirte something");

可以持续写入

可以通过监听流的open和close事件来监听流的打开和关闭

1
2
3
4
5
6
7
ws.on("open", function(){
...
});
ws.once("open", function(){
...
//只触发一次
});

关闭要用end不能用close

1
ws.end();

简单文件读取

1
2
3
4
5
6
fs.readFile("an.jpg", function(err,data){
fs.writeFile("hello.jpg", data, function(){
console.log("写入成功");
//类似复制操作
});
});

流式文件读取

1
2
3
4
5
6
7
8
var rs = fs.createReadStream("an.jpg");

rs.once("open", function(){

});
rs.once("close", function(){

});

如果读取通过可读流读取数据, 必须绑定一个data事件, 绑定完毕, 会自动开始读取数据

数据为回调函数

1
2
3
4
5
6
7
8
9
10
11
var ws = fs.createWriteStream(a.mp3);

rs.on("data",function(data){
console.log(data);//以字节文件形式储存
//写入读取到的数据
ws.write(data);
});
rs.once("close", function(){
console.log("可读流关闭里");
ws.end;
});

更简单的方法

1
rs.pipe(ws);

pipe可以直接将可读流中的内容直接输出到可写流中;

其他file方法

  • fs.exits(path, callback);

  • fs.stat();

    • 返回一个对象, 有对象状态相关信息
  • fs.unlink(path, callback)

    • 删除文件
  • fs.readdir(“.”, function(err, files){})

    • files 是文件数组
  • fs.truncateSync(“hello.txt”, 10)

    • 截断文件, 设置文件成指定大小
  • fs.mkdir(path[, mode], callback)

    • 创建目录
  • fs.rmdir(path[, mode], callback)

  • fs.rename(oldPath, newPath, callback)

    • 重命名
    • 也可以间接实现剪切操作
  • fs.watchFile(filename[, options], listener)

    • 监视文件的修改
    • 参数:
      • filename
      • options
      • listener 回调函数, 文件发生时, 函数会被执行
        • 有两个参数:
        • curr
        • prev
        • 都是stats对象
Author: klenq
Link: https://klenq.github.io/2021/11/09/NodeJS学习笔记/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.