快速入门:理解 node js 背景和基本特性。了解核心模块及应用。
简介
- 在浏览器之外运行 v8 引擎。
- nodejs 运行于单个进程。
- 事件循环-非阻塞。
- 09年诞生,创建了npm第一版。
- 重大区别
- 不同的生态:例如 window/global一起其他api。
- node 可以控制运行环境。
- 模块化方案。
- v8 JavaScript 引擎独立于托管它的浏览器。 此关键的特性推动了 Node.js 的兴起
- JavaScript 通常被认为是一门解释型的语言,但是现代的 JavaScript 引擎不再只是解释 JavaScript,也会对其进行编译。JavaScript 是由 V8 在其内部编译的,使用了即时(JIT)编译以加快执行速度。
关键特性
退出 nodejs 程序
利用 process.exit()
退出程序,也可以发送退出码,给其他进程使用:process.exit(1)
,通常 0 代表成功。
也可以利用 process.exitCode = 1
设置退出码,再退出。
也可以从其他程序,或者运行中的程序发出退出指令:process.kill(process.pid, 'SIGTERM')
。
读取环境变量
利用 process.env
属性设置/获取环境变量,比如:process.env.NODE_ENV = development
。
从命令行接收参数
利用 process.argv
属性获取命令行参数,例如:
node index.js name=mx
//index.js
const args = process.argv
console.log(args)//[路径,路径,'name=mx']
- 第一个参数是
node
命令的完整路径。 - 第二个参数是正被执行的文件的完整路径。
- 所有其他的参数从第三个位置开始。
协助获取命令行参数的库:minimist
、yargs
node 输出到命令行
常规用法和js一致,另外可以利用插件实现更更富的输出,比如进度条 progress
插件。
node cli 交互
如何实现:提示请输入密码?并获取密码的功能。
利用 readline
模块即可实现按行读取输入流的功能:
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
})
readline.question(`你叫什么名字?`, name => {
console.log(`你好 ${name}!`)
readline.close()
})
不仅是简单的问询,readline 还提供有其他交互功能。
inquirer
则提供了更完善,更抽象的功能:
const inquirer = require('inquirer')
var questions = [
{
type: 'input',
name: 'name',
message: "你叫什么名字?"
}
]
inquirer.prompt(questions).then(answers => {
console.log(`你好 ${answers['name']}!`)
})
例如询问多项选择、展示单选按钮、确认等。
npm 与 npx
npm 安装路径问题、如何更新、卸载、packagejson的api。
npx 直接执行某个命令库,而无需下载,并且可以直接运行 github 中的代码。
npx 解决得两个主要问题:
- 同一个包的不同版本无法使用 npm 同时执行
- 可以运行非npm 库的代码。
例如直接运行
npx cowsay "你好"
打印如下:
npx: installed 10 in 6.641s
______
< 你好 >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
npx node@10 -v #v10.18.1
npx node@12 -v #v12.14.1
事件循环
- 调用栈
- 事件循环模型
- 消息队列:setTimeout/setImmediate
- 作业队列:Promise、process.nextTick
关键理解作业队列和消息队列的区别。不是单纯的先后顺序。
作业队列是在当前循环之后立即执行、消息队列则是在下一次循环中执行的。
异步编程
promise/async/await/
事件触发器
events
模块提供了时间触发处理逻辑。
const EventEmitter = require('events')
const eventEmitter = new EventEmitter()
eventEmitter.on('start', number => {
console.log(`开始 ${number}`)
})
eventEmitter.emit('start', 23)
搭建 HTTP 服务器
利用 http
模块搭建 http 服务器:
const http = require('http')
const port = 3000
const server = http.createServer((req, res) => {
res.statusCode = 200
res.setHeader('Content-Type', 'text/plain')
res.end('你好世界\n')
})
server.listen(port, () => {
console.log(`服务器运行在 http://${hostname}:${port}/`)
})
http
模块还可以用来发送和响应POST请求。
文件
使用文件描述符
const fs = require('fs')
try {
const fd = fs.openSync('/Users/joe/test.txt', 'r')
} catch (err) {
console.error(err)
}
- r+ 打开文件用于读写。
- w+ 打开文件用于读写,将流定位到文件的开头。如果文件不存在则创建文件。
- a 打开文件用于写入,将流定位到文件的末尾。如果文件不存在则创建文件。
- a+ 打开文件用于读写,将流定位到文件的末尾。如果文件不存在则创建文件。
文件属性
fs
的 state()
方法可以获取文件属性:
const fs = require('fs')
try {
const stats = fs.statSync('/Users/joe/test.txt')
} catch (err) {
console.error(err)
}
例如:
- 使用
stats.isFile()
和stats.isDirectory()
判断文件是否目录或文件。 - 使用
stats.isSymbolicLink()
判断文件是否符号链接。 - 使用
stats.size
获取文件的大小(以字节为单位)。
文件路径
使用 path
模块管理文件路径:
const path = require('path')
dirname
: 获取文件的父文件夹。basename
: 获取文件名部分。extname
: 获取文件的扩展名。
例如:
const notes = '/users/joe/notes.txt'
path.dirname(notes) // /users/joe
path.basename(notes) // notes.txt
path.extname(notes) // .txt
path.join()
连接路径path.resolve()
获得相对路径的绝对路径计算path.normalize()
计算实际路径:path.normalize('/users/joe/..//test.txt') //'/users/test.txt'
读写文件
const fs = require('fs')
fs.readFile('/Users/joe/test.txt', 'utf8' , (err, data) => {
if (err) {
console.error(err)
return
}
console.log(data)
})
const content = '一些内容'
fs.writeFile('/Users/joe/test.txt', content, err => {
if (err) {
console.error(err)
return
}
//文件写入成功。
})
文件夹
使用 fs.access()
检查文件夹是否存在以及 Node.js 是否具有访问权限。
使用 fs.mkdir()
或 fs.mkdirSync()
可以创建新的文件夹。
使用 fs.readdir()
或 fs.readdirSync()
可以读取目录的内容。
使用 fs.rename()
或 fs.renameSync()
可以重命名文件夹。
使用 fs.rmdir()
或 fs.rmdirSync()
可以删除文件夹。
核心模块
- fs 文件系统模块
- path 路径模块
- os 操作系统模块
- events 事件模块
- http 模块
- Buffer 模块
- 流:
[stream](http://nodejs.cn/api/stream.html)
模块 提供了构建所有流 API 的基础
这些模块是nodejs 的重要模块,有必要完整的整理这些模块的功能点。