node.js 初探
node.js 是一个 JS 的服务端运行环境,简单的来说,他 是在 JS 语言规范的基础上,封装了一些服务端的运行时 对象,让我们能够简单实现非常多的业务功能
如果我们只使用 JS 的话,实际上只是能进行一些简单的 逻辑运算。node.js 就是基于 JS 语法增加与操作系统之 间的交互。
node.js 的安装
我们可以使用多种方式来安装 node.js,node.js 本质上 也是一种软件,我们可以使用直接下载二进制安装文件 安装,通过系统包管理进行安装或者通过源码自行编译 均可。
一般来讲,对于个人开发的电脑,我们推荐直接通过 node.js 官网的二进制安装文件来安装。对于打包上线 的一些 node.js 环境,也可以通过二进制编译的形式来 安装。
安装成功之后,我们的 node 命令就会自动加入我们的 系统环境变量 path 中,我们就能直接在全局任意位 置,使用 node 命令访问到我们刚才安装的 node 可执 行命令行工具。
node.js 版本切换
在个人电脑上,我们可以安装一些工具,对 node.js 版本进行切换,例如 nvm 和 n。
nvm 的全称就是 node version manager,意思就是能 够管理 node 版本的一个工具,它提供了一种直接通过 shell 执行的方式来进行安装。简单来说,就是通过将多 个 node 版本安装在指定路径,然后通过 nvm 命令切换 时,就会切换我们环境变量中 node 命令指定的实际执 行的软件路径。
curl -o-
https://raw.githubusercontent.com/nvm-
sh/nvm/v0.35.3/install.sh | bash
安装成功之后,我们就能在当前的操作系统中使用多个 node.js 版本。
node.js 的包管理工具 npm
我们对 npm 应该都比较熟悉了,它是 node.js 内置的 一款工具,目的在于安装和发布符合 node.js 标准的模 块,从而实现社区共建的目的繁荣整个社区。
npx 是 npm@5 之后新增的一个命令,它使得我们可以 在不安装模块到当前环境的前提下,使用一些 cli 功能。
# 此时全局安装了 create-react-app npm i -g create-react-app create-react-app some-repo
# 此时无论是项目中还是全局都没有安装 create- react-app (但实际上是安装了的,但表现确实像没有安 装)
npx create-react-app some-repo
node.js 的底层依赖
node.js 的主要依赖子模块有以下内容:
- V8 引擎:主要是 JS 语法的解析,有了它才能识别 JS 语法
- libuv: c 语言实现的一个高性能异步非阻塞 IO 库,用 来实现 node.js 的事件循环
- http-parser/llhttp: 底层处理 http 请求,处理报文, 解析请求包等内容
- openssl: 处理加密算法,各种框架运用广泛
- zlib: 处理压缩等内容
node.js 常⻅内置模块
node.js 中最主要的内容,就是实现了一套 CommonJS 的模块化规范,以及内置了一些常⻅的模块。
- fs: 文件系统,能够读取写入当前安装系统环境中硬盘的数据
const fs = require('fs')
const fsP = require('fs').promises
// 创建文件夹
fs.mkdir('./logs', (err) => {
console.log('done.')
})
// 文件夹改名
fs.rename('./logs', './log', () => {
console.log('done')
})
// 删除文件夹
fs.rmdir('./log', () => {
console.log('done.')
})
// 写内容到文件里
fs.writeFile(
'./logs/log1.txt',
'hello',
// 错误优先的回调函数
(err) => {
if (err) {
console.log(err.message)
} else {
console.log('文件创建成功')
}
}
)
// 给文件追加内容
fs.appendFile('./logs/log1.txt', '\nworld', () => {
console.log('done.')
})
// 读取文件内容
fs.readFile('./logs/log1.txt', 'utf-8', (err, data) => {
console.log(data)
})
// 删除文件
fs.unlink('./logs/log1.txt', (err) => {
console.log('done.')
})
// 批量写文件
for (var i = 0; i < 10; i++) {
fs.writeFile(`./logs/log-${i}.txt`, `log-${i}`, (err) => {
console.log('done.')
})
}
// 读取文件/目录信息
fs.readdir('./', (err, data) => {
data.forEach((value, index) => {
fs.stat(`./${value}`, (err, stats) => {
// console.log(value + ':' + stats.size)
console.log(value + ' is ' + (stats.isDirectory() ? 'directory' : 'file'))
})
})
})
// 同步读取文件
try {
const content = fs.readFileSync('./logs/log-1.txt', 'utf-8')
console.log(content)
console.log(0)
} catch (e) {
console.log(e.message)
}
console.log(1)
// 异步读取文件:方法一
fs.readFile('./logs/log-0.txt', 'utf-8', (err, content) => {
console.log(content)
console.log(0)
})
console.log(1)
// 异步读取文件:方法二
fs.readFile('./logs/log-0.txt', 'utf-8').then(result => {
console.log(result)
})
// 异步读取文件:方法三
function getFile() {
return new Promise((resolve) => {
fs.readFile('./logs/log-0.txt', 'utf-8', (err, data) => {
resolve(data)
})
})
}
;(async () => {
console.log(await getFile())
})()
// 异步读取文件:方法四
const fsp = fsP.readFile('./logs/log-1.txt', 'utf-8').then((result) => {
console.log(result)
})
console.log(fsP)
// watch 监测文件变化
fs.watch('./logs/log-0.txt', () => {
console.log(0)
})
// 目录遍历的方法
function readDir(dir) {
fs.readdir(dir, (err, dirs) => {
dirs.forEach((value, index) => {
let joinDir = `${dir}/${value}`;
fs.stat(joinDir, (err1, stats) => {
if (stats.isDirectory()) {
readDir(joinDir)
} else {
fs.readFile(joinDir, (err, values) => {
console.log(values.toString());
})
}
})
})
})
}
readDir('./')
-
path: 路径系统,能够处理路径之间的问题
const path = require('path') path.resolve(__dirname, './index.js'); path.join('a','b','c')
-
crypto: 加密相关模块,能够以标准的加密方式对我们的内容进行加解密
const crypto = require('crypto') const secret = 'abcdefg' const hash = crypto.createHmac('sha256', secret) .update('I love you') .digest('hex') console.log(hash)
-
dns: 处理 dns 相关内容,例如我们可以设置 dns 服 务器等等
-
http: 设置一个 http 服务器,发送 http 请求,监听 响应等等
const http = require("http") http.createServer((req,res) => { res.writeHead(200, { "content-type": "text/plain" }) res.write("hello nodejs") res.end() }).listen(3000)
-
readline: 读取 stdin 的一行内容,可以读取、增加、 删除我们命令行中的内容
const readline = require('readline') const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) rl.question('What do you think of Node.js? ', (answer) => { // TODO: Log the answer in a database console.log(`Thank you for your valuable feedback: ${answer}`) rl.close() })
-
os: 操作系统层面的一些 api,例如告诉你当前系统类 型及一些参数
-
vm: 一个专⻔处理沙箱的虚拟机模块,底层主要来调 用 v8 相关 api 进行代码解析
node.js CommonJS 详解及源码解析
创建三个文件分别命名为index.js, module.js,require.js
index.js内容:
require('./require');
const result = r('./module.js');
console.log(result);
module.js
module.exports = "hello world";
Require.js
const vm = require('vm');
const fs = require('fs');
const path = require('path');
function r(filename) {
const pathToFile = path.resolve(__dirname, filename);
const content = fs.readFileSync(pathToFile, 'utf-8');
const wrapper = [
'(function(require, module, exports, __dirname, __filename) {',
'})'
]
const wrapperContent = wrapper[0] + content + wrapper[1];
const script = new vm.Script(wrapperContent, {
filename: 'index.js'
});
const module = {
exports: {}
}
const result = script.runInThisContext();
result(r, module, module.exports, null, null);
return module.exports;
}
global.r = r;