Node.js
1. Node.js 概述
node.js
是一个基于V8引擎的JavaScript
运行环境,用于构建高速、可伸缩的网络应用程序。Node.js采用的事件驱动、非阻塞I/O模型,使它既轻量又高效,是构建可扩展的网络应用程序的完美选择。
1.1 JavaScript引擎
JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器中:
V8
引擎:Chrome浏览器采用的JavaScript引擎,也是第一个使用JIT技术的引擎;JavaScriptCore
引擎:Safari浏览器;Chakra
引擎:IE / Edge浏览器;SpiderMonkey
引擎:Mozilla Firefox浏览器。
1.2 事件驱动
事件驱动程序设计(Event-Driven Programming)是一种计算机程序设计模型。这种程序的运行流程是靠用户的操作(如点击鼠标、敲击键盘等)或者是由其他程序的消息来驱动的。
事件驱动程序至少要有一个事件队列,当有新的请求时会被插入事件队列中,然后通过循环来检测队列中的事件(Node.js
的JavaScript是单线程运行的),当有事件发生时就会调用回调函数(处理事件)。
1.3 非阻塞I/O
I/O模型的一种,与之对应的还有阻塞I/O。
1.4 Node.js的模块架构
Node.js
核心基于libuv
框架,由C/C++编写。libuv
是一个提供异步功能的C库。它在运行时负责一个事件循环(Event Loop
)、一个线程池、文件系统I/O、DNS相关的I/O和网络I/O,以及一些其他重要功能。
1.5 Node.js 标准库
标准库由JavaScript编写而成,提供网络、文件、事件等操作。
2. Node.js 运行原理
Node.js
应用启动时,会开启JS
线程(主线程)、由libuv
提供的线程池和一个事件循环(Event Loop
)。JS
线程负责执行应用代码,当发现有I/O操作时,直接提交给libuv
的线程池并注册回调函数,不会等I/O结束后再继续运行,而是拿到一个状态后继续执行,这就是单线程非阻塞I/O。
I/O操作结束后会有一个事件,该事件放在Event Loop
中,事件循环每次都会检查是否有事件需要处理,如果有就处理,否则进行下一轮询,如果没有任何事件需要处理就退出进程。这就是事件驱动。
在I/O密集型任务中,主线程只负责提交任务、轮询结果,耗时的任务交给底层执行,这就是Node.js
高效的原因。
3. Node.js 的模块系统
Node.js
由模块组成,采用CommandJS
模块规范。每个JS文件就是一个模块,有独立的作用域。在一个文件中定义的变量、函数、类在其他文件都不可见。
3.1 module和exports
CommandJS
规范规定,每个模块内部的变量module
代表当前模块。module
是一个对象,module.exports
是对外的接口。加载模块实际上是读取该模块的module.exports
属性。
module.exports
也是一个对象,所有需要导出的变量、函数、类都需要挂载到该对象上才能实现导出。
// example.js
function sum(a, b){
return a + b;
}
module.exports.sum = sum;
// 或者 exports.sum = sum;
Node.js
为每个模块都提供了exports
变量,在同一个模块中,module.exports
和exports
是恒等的,在原理上,等同于:
let exports = module.exports;
CommandJS
规范规定require
用于加载模块文件,返回该模块文件的exports对象
,模块未找到就会抛出错误。
// index.js
let sum = require('./example').sum;
console.log(sum(3, 4));
3.2 来个实例
开发一个与时间操作有关的函数模块:
- data.js
exports.formatTime = function(timestamp){
const duration = parseInt(Data.now() / 1000, 10) - timestamp;
if (duration < 600){
return '刚刚';
}
if (duration < 3600){
return '1小时内';
}
if (duration < 3600 * 3){
return '3小时内';
}
if (duration < 3600 * 24){
return '今天';
}
if (duration < 3600 * 24 * 2){
return '一天前';
}
}
return new Date(timestamp * 1000).toString();
- index.js
const date = require('./date');
const now = parseInt(Date.now() / 1000, 10);
console.log(date.formatTime(now - 60));
console.log(date.formatTime(now - 600));
console.log(date.formatTime(now - 5400));
console.log(date.formatTime(now - 3600 * 23));
console.log(date.formatTime(now - 3600 * 24));
console.log(date.formatTime(now - 3600 * 24 * 3));
在终端执行:
>>> node index.js
刚刚
1小时内
3小时内
今天
1天前
Mon Oct 23 2021 18:07:45 GMT+0800 (中国标准时间)