背景
在前端历史演变中已经提到,Nodejs 的爆发从 2009 年开始。Nodejs 的出现,基于作者 Ryan Dahl 对 Web 开发高性能的追求,要达到高性能,异步 IO/ 事件驱动是基本原则。对比一些高级语言,最终选择 Javascript 作为开发语言, 由于 Javascript 天生的事件驱动和单线程,奠定了 Nodejs 编写高性能 Web 服务轻而易举。
简单了解 Nodejs
Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行环境 。
Node.js 使用了一个 事件驱动 、 非阻塞式 I/O 的模型,使其轻量又高效。
以上是官方给出的解释,惯例我们还是抽取关键词理解。
Chrome V8 引擎介绍
V8 引擎是 Chrome 于 2008 年 9 月 2 日发布开源。V8 使用 C ++ 开发,相比其它的 JavaScript 的引擎转换成字节码或解释执行,V8 将其编译成原生机器码(IA-32, x86-64, ARM, or MIPS CPUs),并且使用了如内联缓存(inline caching)等方法来提高性能。有了这些功能,JavaScript 程序在 V8 引擎下的 运行速度媲美二进制程序 。
Chrome 浏览器在 Webkit 渲染引擎中使用 v8 引擎来提高浏览器的渲染性能。
上图是 webkit 大致结构,红色部分是 webkit 的默认引擎,在谷歌系列产品中被替换为 v8 引擎;
Nodejs 是站在“巨人的肩膀”上进行一系列的封装,它的高性能,离不开 Chorme V8 引擎。
JavaScript 运行环境
Javascript 是一个静态脚本语言,运行时必须要借助于引擎才能运行。
Javascript 运行环境一般分为两种:
- 浏览器运行环境(通常我们写的 js 代码要在浏览器中才能运行)
- 非浏览器运行环境(比如 Nodejs, 借助于 V8 引擎实现运行的环境)
事件驱动
我们在 Javascript 中注册个事件(回调函数)。但这个事件不是马上执行。只有等事件被触发的时候,才会去执行这个事件(回调函数)。这种形式就是事件驱动。
非阻塞 I/O
阻塞:前一个程序未执行完就得一直等待。比如当你打电话问个问题时,那边说你等等我给你查查,这时候你电话仍然是挂起的,等待等待,直到拿到结果。
非阻塞:前一个程序未执行完时可以挂起,继续执行其他程序,等到使用时再执行。比如当你打电话过去问一个问题,然后挂电话,等那边找到结果就打电话给你。查问题这段时间,你该干嘛就干嘛。
I/O: 磁盘的写入(in)磁盘的读取(out)。在程序执行过程中必然要进行很多 I / O 操作,读写文件、输入输出、请求响应等等。I/ O 操作时最费时,举个例子,你要读一个文件,整个线程都暂停下来,等待文件读完后继续执行。换言之,I/ O 操作阻塞了代码的执行,极大地降低了程序的效率。
在 Nodejs 里面单线程可以通过回调函数(事件驱动)来做异步操作,达到非阻塞 I / O 的效果。
安装 Nodejs
- 可以在官网自行选择安装包下载
- MacOS 用户建议使用 brew 安装
# 安装
brew install -g node
#卸载
brew uninstall nodejs
- 使用 nvm 安装管理 Nodejs 版本
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
# or
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
# 放入环境变量
source ~/.bash_profile
# 判断是否安装成功
nvm list
# 安装 node
nvm install 6.14.4 # or 10.10.0, 8.9.1, etc
# 判断 node 安装成功
node -v
npm -v
Nodejs 的简单使用
模块化规范 CommonJs
在前端模块化中已经对 CommonJs 做了介绍,并使用 exports 导出模块,require 引入模块,实现了一个简单案例。
- require: 引入一个模块
- exports: 导出模块内容
- module: 模块本身
使用 Nodejs 创建服务
// index.js
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port, hostname, () => {console.log(`Server running at http://${hostname}:${port}/`);
});
运行 node index.js
会起一个去 127.0.0.1:3000
的服务,并在浏览器中输出Hello world
了解基础 API
path
模块提供用于处理文件路径和目录路径的实用工具。
// 引用
const path = require('path');
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// 返回: '/foo/bar/baz/asdf'
// path.resolve() 方法将路径或路径片段的序列解析为绝对路径
path.resolve('/foo/bar', './baz');
// 返回: '/foo/bar/baz'
fs
文件系统模块,对文件和目录进行读写操作。
// 引用
const fs = require('fs');
// 读取文件
fs.readFile('./test.txt', function(err, data) {if (err) {throw err;}
console.log(data);
});
// 写入文件
fs.writeFile('input.txt', '我是新写入的内容', function (err) {if (err) console.error(err);
console.log('数据写入的数据');
});
// 删除
fs.unlink('/tmp/hello', (err) => {if (err) throw err;
console.log('已成功删除 /tmp/hello');
});
// 重命名
fs.rename('/tmp/hello', '/tmp/world', (err) => {if (err) throw err;
console.log('重命名完成');
});
更多 Api
参考 Nodejs Api 官网。
参考:
Chrome V8 引擎介绍
百度百科 V8 介绍
Nodejs 官网指南