快速入门:理解 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.jsconst args = process.argvconsole.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.1npx 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 = 3000const server = http.createServer((req, res) => {res.statusCode = 200res.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/joepath.basename(notes) // notes.txtpath.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 的重要模块,有必要完整的整理这些模块的功能点。
