快速入门:理解 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 属性获取命令行参数,例如:

  1. node index.js name=mx
  1. //index.js
  2. const args = process.argv
  3. console.log(args)//[路径,路径,'name=mx']
  1. 第一个参数是 node 命令的完整路径。
  2. 第二个参数是正被执行的文件的完整路径。
  3. 所有其他的参数从第三个位置开始。

协助获取命令行参数的库:minimistyargs

node 输出到命令行

常规用法和js一致,另外可以利用插件实现更更富的输出,比如进度条 progress 插件。

node cli 交互

如何实现:提示请输入密码?并获取密码的功能。

利用 readline 模块即可实现按行读取输入流的功能:

  1. const readline = require('readline').createInterface({
  2. input: process.stdin,
  3. output: process.stdout
  4. })
  5. readline.question(`你叫什么名字?`, name => {
  6. console.log(`你好 ${name}!`)
  7. readline.close()
  8. })

不仅是简单的问询,readline 还提供有其他交互功能。

inquirer 则提供了更完善,更抽象的功能:

  1. const inquirer = require('inquirer')
  2. var questions = [
  3. {
  4. type: 'input',
  5. name: 'name',
  6. message: "你叫什么名字?"
  7. }
  8. ]
  9. inquirer.prompt(questions).then(answers => {
  10. console.log(`你好 ${answers['name']}!`)
  11. })

例如询问多项选择、展示单选按钮、确认等。

npm 与 npx

npm 安装路径问题、如何更新、卸载、packagejson的api。

npx 直接执行某个命令库,而无需下载,并且可以直接运行 github 中的代码。

npx 解决得两个主要问题:

  1. 同一个包的不同版本无法使用 npm 同时执行
  2. 可以运行非npm 库的代码。

例如直接运行

  1. npx cowsay "你好"

打印如下:

  1. npx: installed 10 in 6.641s
  2. ______
  3. < 你好 >
  4. ------
  5. \ ^__^
  6. \ (oo)\_______
  7. (__)\ )\/\
  8. ||----w |
  9. || ||
  1. npx node@10 -v #v10.18.1
  2. npx node@12 -v #v12.14.1

事件循环

  • 调用栈
  • 事件循环模型
  • 消息队列:setTimeout/setImmediate
  • 作业队列:Promise、process.nextTick

关键理解作业队列和消息队列的区别。不是单纯的先后顺序。

作业队列是在当前循环之后立即执行、消息队列则是在下一次循环中执行的。

异步编程

promise/async/await/

事件触发器

events 模块提供了时间触发处理逻辑。

  1. const EventEmitter = require('events')
  2. const eventEmitter = new EventEmitter()
  3. eventEmitter.on('start', number => {
  4. console.log(`开始 ${number}`)
  5. })
  6. eventEmitter.emit('start', 23)

搭建 HTTP 服务器

利用 http 模块搭建 http 服务器:

  1. const http = require('http')
  2. const port = 3000
  3. const server = http.createServer((req, res) => {
  4. res.statusCode = 200
  5. res.setHeader('Content-Type', 'text/plain')
  6. res.end('你好世界\n')
  7. })
  8. server.listen(port, () => {
  9. console.log(`服务器运行在 http://${hostname}:${port}/`)
  10. })

http 模块还可以用来发送和响应POST请求。

文件

使用文件描述符

  1. const fs = require('fs')
  2. try {
  3. const fd = fs.openSync('/Users/joe/test.txt', 'r')
  4. } catch (err) {
  5. console.error(err)
  6. }
  • r+ 打开文件用于读写。
  • w+ 打开文件用于读写,将流定位到文件的开头。如果文件不存在则创建文件。
  • a 打开文件用于写入,将流定位到文件的末尾。如果文件不存在则创建文件。
  • a+ 打开文件用于读写,将流定位到文件的末尾。如果文件不存在则创建文件。

文件属性

fsstate() 方法可以获取文件属性:

  1. const fs = require('fs')
  2. try {
  3. const stats = fs.statSync('/Users/joe/test.txt')
  4. } catch (err) {
  5. console.error(err)
  6. }

例如:

  • 使用 stats.isFile()stats.isDirectory() 判断文件是否目录或文件。
  • 使用 stats.isSymbolicLink() 判断文件是否符号链接。
  • 使用 stats.size 获取文件的大小(以字节为单位)。

文件路径

使用 path 模块管理文件路径:

  1. const path = require('path')
  • dirname: 获取文件的父文件夹。
  • basename: 获取文件名部分。
  • extname: 获取文件的扩展名。

例如:

  1. const notes = '/users/joe/notes.txt'
  2. path.dirname(notes) // /users/joe
  3. path.basename(notes) // notes.txt
  4. path.extname(notes) // .txt
  • path.join() 连接路径
  • path.resolve() 获得相对路径的绝对路径计算
  • path.normalize() 计算实际路径:path.normalize('/users/joe/..//test.txt') //'/users/test.txt'

读写文件

  1. const fs = require('fs')
  2. fs.readFile('/Users/joe/test.txt', 'utf8' , (err, data) => {
  3. if (err) {
  4. console.error(err)
  5. return
  6. }
  7. console.log(data)
  8. })
  9. const content = '一些内容'
  10. fs.writeFile('/Users/joe/test.txt', content, err => {
  11. if (err) {
  12. console.error(err)
  13. return
  14. }
  15. //文件写入成功。
  16. })

文件夹

使用 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 的基础
  1. 这些模块是nodejs 的重要模块,有必要完整的整理这些模块的功能点。