Nodejs 架构

NUC13 bios界面_前端

Natives modules

当前层内容由 JS 实现。

提供应用程序可直接调用库,例如 fs、path、http等。

JS 语言无法直接操作底层硬件设置。需要通过桥梁:Builtin modules "胶水层" (由C++编写)。

底层

V8:执行 JS 代码,提供桥梁接口。

Libuv: 事件循环、事件队列、异步IO

第三方模块:zlib、http、c-ares等。

NUC13 bios界面_前端_02

Reactor模式

单线程完成多线程工作

实现异步IO、事件驱动

可以实现高并发处理

Nodejs 更适用于 IO 密集型高并发请求

Nodejs异步IO

nodejs异步 IO 是 异步非阻塞 IO

立即返回的并不是业务层期望得到的数据,而仅仅是当前调用的状态,操作系统为了获取数据,就会让程序重复调用IO操作,判断 IO 是否结束,这种技术称为轮询。

常见轮询技术:read、select、poll、kqueue、event ports

期望实现无需主动判断的非阻塞 IO

NUC13 bios界面_前端_03

 1

NUC13 bios界面_javascript_04

异步 IO 总结

IO 是异步程序的瓶颈所在

异步 IO 提高性能无须采用原地等待结果返回

IO 操作属于操作系统级别,平台都有对应实现

Nodejs 单线程配合事件驱动架构及libuv实现了异步 IO

Nodejs 事件驱动架构

事件驱动架构是软件开发中的通用模式

事件驱动、发布订阅、观察者

主体发布消息,其他实例接收消息

const EventEmitter = require('events')

const myEvent = new EventEmitter()

myEvent.on('事件1', () => {
  console.log('事件1执行了')
})

myEvent.on('事件1', () => {
  console.log('事件1-2执行了')
})

myEvent.emit('事件1')

输出:

NUC13 bios界面_NUC13 bios界面_05

Nodejs单线程

使用 JS 实现高效可伸缩的高性能 Web 服务

单线程如何实现高并发?

异步非阻塞 IO 配合事件回调通知

Nodejs 主线程是单线程

libuv 库会维护一个线程池

NUC13 bios界面_单线程_06

 1

const http = require('http')

function sleepTime (time) {
  const sleep = Date.now() + time * 1000
  while(Date.now() < sleep) {}
  return 
}
sleepTime(4)
const server = http.createServer((req, res) => {
  res.end('server starting......')
})

server.listen(8080, () => {
  console.log('服务启动了')
})

4秒后服务启动

Nodejs应用场景

IO 密集型高并发请求

Nodejs作为中间层

NUC13 bios界面_javascript_07

操作数据库提供 API 服务

实时聊天应用程序

Nodejs 更加适合 IO 密集型任务

Nodejs实现API服务

// 需求:希望有一个服务,可以依据请求的接口内容返回相应的数据
import express from 'express'
import { DataStore } from './data'

const app = express()

app.get('/', (req, res) => {
  // res.end('1122')
  res.json(DataStore.list)
})

app.listen(8081, () => {
  console.log('服务已经开启了')
})

Nodejs全局对象

与浏览器平台的 window 不完全相同

Nodejs 全局对象上挂载许多属性

全局对象是 JavaScript 中的特殊对象

Node.js 中全局对象是 global

Global 的根本作用就是作为宿主

全局对象可以看做是全局变量的宿主

默认情况 this 是空对象,和 global 并不是一样的

Nodejs 常见全局变量

__filename:返回正在执行脚本文件的绝对路径

__dirname:返回正在执行脚本所在目录

timer类函数:执行顺序与事件循环间的关系

process:提供与当前进程互动的接口

require:实现模块的加载

module、exports:处理模块的导出

Nodejs 常见全局变量-process

获取进程信息

执行进程操作

// 1 资源: cpu 内存
console.log(process.memoryUsage())  // 内存信息
/*
{
  rss: 24449024,        // 常驻内存
  heapTotal: 4481024,   // 脚本执行申请的内存总大小
  heapUsed: 2822984,    // 脚本执行过程中实际使用的内存大小
  external: 938610,     // 底层c++模块所占用的内存大小
  arrayBuffers: 9898    // Buffer 独立占用的缓冲区内存大小
}
*/


console.log(process.cpuUsage())  // cpu 信息
/*
{ 
  user: 31000,        // 用户执行过程中所占用的cpu时间片段
  system: 46000       // 操作系统所占用的cpu时间片段
}
*/


// 2 运行环境:运行目录、node环境、cpu架构、用户环境、系统平台
console.log(process.cwd())            // 当前工作目录
// D:\s\lagou\5\1\5-1-课程资料\Code\01Base


console.log(process.version)          // 当前node版本
//v14.18.1


console.log(process.versions)         // node 其他相关版本信息
/*
{
  node: '14.18.1',
  v8: '8.4.371.23-node.84',
  uv: '1.42.0',
  zlib: '1.2.11',
  brotli: '1.0.9',
  ares: '1.17.2',
  modules: '83',
  nghttp2: '1.42.0',
  napi: '8',
  llhttp: '2.1.4',
  openssl: '1.1.1l',
  cldr: '39.0',
  icu: '69.1',
  tz: '2021a',
  unicode: '13.0'
}
*/


console.log(process.arch)             // 本机操作系统信息
// x64


console.log(process.env.NODE_ENV)    // 获取当前环境,例如:dev、prod


console.log(process.env.PATH)        // 获取本机所配置的系统环境变量
/*
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;D:\微信web开
发者工具\dll;C:\Users\zxy\AppData\Local\Microsoft\WindowsApps;C:\Users\zxy\AppData\Roaming\npm;C:\Users\zxy\AppData\Local\Programs\Microsoft VS Code\bin
*/


console.log(process.env.USERPROFILE)  // 获取本机的管理员目录 mac系统使用 process.env.HOME
// C:\Users\zxy


console.log(process.platform)         // 获取本机操作系统
// win32




// 3 运行状态: 启动参数、PID、运行时间
console.log(process.argv)  // 获取启动参数
/*
PS D:\s\lagou\5\1\5-1-课程资料\Code\01Base> node .\05-process.js 1 2

[
  'C:\\Program Files\\nodejs\\node.exe',      // 当前Node启动程序的完整路径
  'D:\\s\\lagou\\5\\1\\5-1-课程资料\\Code\\01Base\\05-process.js',  // 当前进程文件的路径
  '1',
  '2'
]
*/


console.log(process.argv0)  // 获取启动参数 第一个参数,只提供了 argv0
// C:\\Program Files\\nodejs\\node.exe


console.log(process.pid)  // 获取当前进程的 pid
// 30024


setTimeout(() => {
  console.log(process.uptime())   // 记录从运行开始到运行结束所消耗的时间
  // 3.0328957
}, 3000)

process 事件

// 事件
process.on('exit', code => {  // code: 退出的状态码
  console.log('exit', code)
  setTimeout(() => {
    console.log(123)  // 未打印,只支持同步代码
  }, 1000)
})

process.on('beforeExit', code => {  // code: 退出的状态码
  console.log('beforeExit', code)
})

console.log('代码执行完了')

/*
代码执行完了
beforeExit 0
exit 0
*/


process.exit()  // 直接退出,不会调用 beforeExit

process 标准输出,输入,错误

// 标准输出,输入,错误
console.log = function(data) {
  process.stdout.write('---' + data + '\n')
}

console.log(11)
console.log(22)

/*
---11
---22
*/

读取文件经过管道输出

const fs = require('fs')
fs.createReadStream('text.txt')
  .pipe(process.stdout)

// 控制台输出文件里的内容

控制台里输入内容 stdin

process.stdin.pipe(process.stdout)

获取控制台输入内容事件 stdin

process.stdin.setEncoding('utf-8')
process.stdin.on('readable', () => {
  let chunk = process.stdin.read()
  console.log(chunk)
})