Skip to content

Nodejs

Node.js简介

什么是 Node.js

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。它允许你使用 JavaScript 编写服务器端的代码,而不仅仅局限于浏览器端。Node.js 提供了许多内置的模块,可以让你轻松地进行文件操作、网络通信等。它的特点是单线程、非阻塞的事件驱动模型,这意味着它可以处理大量的并发请求,使得构建高性能的网络应用变得更加容易。Node.js 是一个开放源代码项目,拥有一个庞大的社区,因此你可以轻松地找到各种各样的工具和库来扩展你的应用。

Node.js 能做什么

Node.js 能做的事情非常多,主要包括以下几个方面:

  1. 构建服务器端应用程序: 你可以使用 Node.js 来创建服务器端的应用程序,比如网站、API(应用程序接口)等。Node.js 提供了一些内置模块,让你能够轻松地处理网络请求、响应、文件操作等。

  2. 开发命令行工具: 你可以使用 Node.js 来开发各种命令行工具,比如自动化任务、构建工具等。Node.js 的模块化系统使得编写和维护这样的工具变得非常简单。

  3. 实时应用程序: Node.js 的事件驱动模型和非阻塞 I/O 特性使得它非常适合构建实时应用程序,比如聊天应用、实时游戏等。你可以轻松地处理大量并发请求,而不会导致性能问题。

  4. 数据流处理: Node.js 提供了流模块,使得处理大量数据流变得非常高效。你可以使用它来处理文件、网络数据等,而不必一次性加载所有数据到内存中。

总的来说,Node.js 是一个非常灵活和强大的工具,你可以用它来构建各种类型的应用程序,从简单的网站到复杂的实时应用程序,都可以轻松应对。

CommonJS

CommonJS 是 JavaScript 社区中一种非常实用的模块化规范,它旨在解决 JavaScript 中,缺乏模块系统、缺少标准库(fs、io)、缺少标准接口(http、数据库)、缺乏包管理系统等等一系列的问题。

Node.js 是目前 CommonJS 规范最热门的一个实现,它基于 CommonJS 的 Modules/1.0 规范实现了 Node.js 的模块,同时随着 CommonJS 规范的更新,Node.js 也在不断跟进。由于目前 CommonJS 大部分规范还在起草阶段,Node.js 已经率先实现了一些功能,并将其反馈给 CommonJS 规范制定组织,但 Node.js 并不完全遵循 CommonJS 规范。这是所有规范制定者都会遇到的尴尬局面,因为规范的制定总是滞后于技术的发展。

安装和配置Node.js

安装Node.js

测试安装是否成功

bash
node -v

输出

v18.14.0

bash
npm -v

输出

9.6.7

配置镜像源

bash
npm config set registry=https://registry.npm.taobao.org

注意

npm的默认镜像源为https://registry.npmjs.org

查看目前的镜像源为npm config get registry

安装第三方包管理器

bash
npm i yarn -g
npm i pnpm -g

Node.js快速入门

Hello World

js
console.log('Hello World');
bash
node hello-world.js

搭建HTTP服务器

js
import http from 'http'

http.createServer((req, res) => {
    res.writeHead(200, {"Content-Type": 'text/html; charset=utf-8'})
    res.write("<h1>Hello Node.js</h1>")
    res.end("<p>Hello World!</p>")
}).listen(3000);

console.log("Nodejs http服务器已经启动")
bash
node http-server.js

模块化开发

历史上,JavaScript一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如RubyrequirePythonimport,甚至就连CSS都有@import,但是JavaScript任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。

html
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>

上面是最原始的 JavaScript 文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在 window 对象中,不同模块的接口调用都是一个作用域中,一些复杂的框架,会使用命名空间的概念来组织这些模块的接口。

这种原始的加载方式暴露了一些显而易见的弊端

  1. 全局作用域下容易造成变量冲突

  2. 文件只能按照 JavaScript 的书写顺序进行加载

  3. 开发人员必须主观解决模块和代码库的依赖关系

  4. 在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪

直到几年前,JavaScript 还没有内置对模块的支持。大型项目的程序员想方设法地利用类、对象和闭包的弱模块化能力。由于打包工具的支持,基于闭包的模块化在实践中成为常用模块化形式,核心是沿用了 Noderequire()函数。基于 require() 的模块是 Node 编程环境的基础,但并未被作为 JavaScript 语言的官方部分采用。事实上,ES6 使用 importexport 关键字定义了自己的模块。尽管 importexport 在多年前就已经被列为这门语言的关键字,但直到最近才真正被浏览器和 Node 实现。实践中,JavaScript 的模块化仍然依赖代码打包工具。

快速入门

js
let username = "张三"
let password = "123456"

export default {username, password}
js
// 注意如果包来源于当前项目(vue、js、node、json)
// 必须采用相对路径的方式引入

// 也就是说如果不采用相对路径的方式
// 默认找到系统模块
// 如果系统模块找不到,那么就在node_modules里边去找
// 如果还找不到,就报错

import person from './person.js'

console.log(person)

Node中的模块

Node的导出

导出多个值(多次导出)
javascript
const sum = (x, y) => x + y;
const square = x => x * x;

// 等同于module.exports.mean
exports.mean = data => data.reduce(sum) / data.length;

// 等同于module.exports.stddev
exports.stddev = function(d) {
  let m = exports.mean(d);
  return Math.sqrt(d.map(x => x - m).map(square).reduce(sum) / (d.length - 1));
};
导出多个值(一次导出)
javascript
const sum = (x, y) => x + y;
const square = x => x * x;

const mean = data => data.reduce(sum) / data.length;

const stddev = function(d) {
  let m = exports.mean(d);
  return Math.sqrt(d.map(x => x - m).map(square).reduce(sum) / (d.length - 1));
};

// 只导出公有函数
module.exports = { mean, stddev };
导出一个值
javascript
module.exports = class BitSet extends AbstractWritableSet {
  // ...
};

Node的导入

Node模块通过调用require()函数导入其他模块。这个函数的参数是要导入模块的名字,返回值是该模块导出的值(通常是一个函数、类或对象)。

如果想导入Node内置的系统模块或通过包管理器安装在系统上的模块,可以使用模块的非限定名,即不带会被解析为文本系统路径的"/"字符的模块名。

javascript
// Node内置的模块
const fs = require("fs");
const http = require("http");

// 不属于Node,但已经安装在本地
const express = require("express");

如果想导入你自己代码中的模块,则模块名应该是指向包含模块代码的模块文件的路径 (相对于当前模块文件)。虽然可以使用以开头的绝对路径,但在导入自己程序的模块时,通常都使用以"./"或"../"开头的模块名,以表示它们相对于当前的目录或父目录。例如:

javascript
const stats = require('./stats.js');
const BitSet = requxre('./utils/bitset.js');

虽然省略导入文件的Js后缀,Node仍然可以找到这些文件,但包含这些文件扩展名还是很常见的。

如果模块只导出一个函数或类,则只要调用require()取得返回值即可。如果模块导出一个带多个属性的对象,则有两个选择:一是导入整个对象;二是 (通过解构赋值)只导入打算使用的特定属性。比较一下这两种方式:

javascript
// 导入整个stats对象,包含所有函数
const stats = requireC./stats.js'); 

// 虽然导入了用不到的函数,但这些函数
// 都隐藏在"stats"命名空间之后 
let average = stats.nean(data);

//当然,也可以使用常见的解构赋值直接 
//向本地命名空间中导入想用的函数:
const { stddev } = require('./stats.js');

// 这样当然简洁明了,只是stddev()函数没有
// 'stats'前缀作为命名空间,因此少了上下文信息 
let sd = stddev(data);

ES6 中的模块

ES6为JavaScript添加了 import 和 export 关键字,终于将模块作为核心语言特性来支持了。ES6模块化与Node的模块化在概念上是相同的:每个文件本身都是模块,在文件中定义的常量、变量,函数和类对这个文件而言都是私有的,除非它们被显式导出。另外,一个模块导出的值只有在显式导入它们的模块中才可以使用。ES6 模块与 Node 模块的区别在于导入和导出所用的语法,以及浏览器中定义模块的方式。

多值导出导入

导出
javascript
export const PI = Math.PI;
export function degreesToRadians(d) ( return d * PI / 180; )
export class Circle {
  constructor(r) { this.r =r; }
  area() ( return PI * this.r * this.r; }
}

注意

以上写法与以下等价

javascript
const PI = Math.PI;
function degreesToRadians(d) ( return d * PI / 180; )
class Circle {
  constructor(r) { this.r =r; }
  area() ( return PI * this.r * this.r; }
}

export { Circle, degreesToRadians, PI };
导入指定值
javascript
import { PI, degressToRadians, Circle } from /stats.js";
导入所有值
javascript
import * as stats from "./stats.js";

默认导出导入

导出
javascript
export default class BitSet {
  // ...
}
导入
javascript
import BitSet from *./bitset.js';

HTML导入

html
<script src="js/app.js" type="module"></script>
html
<script type="module">import ". /main. js";</script>

ES6 的导出

要从ES6模块导出常量,变量、函数或类,只要在声明前加上export关键字即可

javascript
export const PI = Math.PI;
export function degreesToRadians(d) ( return d * PI / 180; )
export class Circle {
  constructor(r) { this.r =r; }
  area() ( return PI * this.r * this.r; }
}

要取代使用多个export关键字的做法,可以先正常定义常量,变量,函数和类,不加 export 关键字。然后(通常在模块末尾)只用一个export语句声明真正要导出的值。 也就是说,前面使用三个export的代码等价于下面这一行代码

javascript
export { Circle, degreesToRadians, PI };

这个语法看起来是export关键字后跟一个对象字面量(使用了简化写法),但这里的花括号实际上不会定义对象字面量。这个导出语法仅仅是要求在一对花括号中给出一个逗号分隔的标识符列表。

一个模块只导出一个值(通常是一个函数或类)的情况是很常见的,此时通常可以使用 export default 而不是 export

javascript
export default class BltSet {
  // ...
}

与非默认导出相比,默认导出(export default)在导入时稍微简单一些。因此在只有一个导出值的情况下,使用 export default 可以简化使用导出值的模块代码。

使用export的常规导出只对有名字的声明有效。而使用export default的默认导出则可以导出任意表达式,包括匿名函数表达式和匿名类表达式。这意味着如果使用export default,则可以导出对象字面量。因此,与export语法不同,位于 export default 后面的花括号是实实在在会被导出的对象字面量。

模块中同时有一些常规导出和一个默认导出是合法的,只是不太常见。如果模块中有默认导出,那就只能有一个。

最后,要注意export关键字只能出现在JavaScript代码的顶层。不能在类,函数、循环或条件内部导出值(这是ES6模块系统的重要特性,用以支持静态分析:模块导出的值在每次运行时都相同,而导出的符号可以在模块实际运行前确定)。

ES6 的导入

默认导入

导入其他模块导出的值要使用import关键字。最简单的形式是导入定义了默认导出的模块

javascript
import BitSet from *./bitset.js';

首先是import关键字,跟着一个标识符,再跟着一个from关键字,最后的字符串字面值是要导入其默认导出的模块的名字。指定模块默认导出的值会变成当前模块中指定标识符的值。

获得导入值的标识符是一个常量,就像是使用const关键字声明的一样。与导出类似,导入也只能出现在模块顶层,不允许在类、函数、循环或条件中出现。按照近似普适的惯例,一个模块所需的导入都应该放在这个模块的开头。不过有意思的是,这个规则并不是强制性的。导入与函数声明类似,会被 “提升”到顶部,因此所有导入的值在模块代码运行时都是可用的。

从中导入值的模块以常量字符串字面量的形式在单引号或双引号中给出(不能使用变量 或其他值作为字符串的表达式,也不能把字符串放在反引号中,因为模板字面量有可 能插入变量,并非只包含常量值)。在浏览器中,这个字符串会被解释为一个相对于导入模块位置的URL (在Node中,或当使用打包工具时,这个字符串会被解释为相对于当前模块的文件名,不过这在实践中没有太大差别)。模块标识符字符串必须是一个以"/"开头的绝对路径,或者是一个以"./"或"../"开头的相对路径,又或者是一个带有协议及主机名的完整URL。ES6规范不允许类似"util.js"的非限定模块标识符字符串,因为它存在歧义:它是当前模块同级目录下的一个模块呢,还是安装在特殊位置的某个系统模块呢?(webpack等代码打包工具不会限制这种"裸模块标识符",因为通过配置很容易在指定的库目录中找到裸模块。)JavaScript语言未来的某个版本可能会允许 "裸模块标识符",但现在还不允许。如果想从当前模块的同级目录导入模块,只需要在模块名前面加上"./",也就是使用"./util.js”而非"util.js"。

导入多个值

到现在为止,我们只考虑了从使用export default的模块导入一个值的情形。要从导出多个值的模块导入值,就要使用稍微不一样的语法

javascript
import { mean, stddev } from /stats.js";

前面提到过,默认导出在定义它们的模块中不需要名字,在导入这些值的时候可以再给它们提供一个局部名。但非默认导出在导出它们的模块中则是有名字的,在导入这些值时,需要通过名字引用它们。导出模块可以导出任意多个命名的值。引用该模块的 import 语句可以导入这些值的任意子集,只要在花括号中列出它们的名字即可。花括号让 import 语句看起来像是解构赋值,而解构赋值也确实是这种导入风格一个不错的类比。花括号中的标识符都会被提升到导入模块顶部,行为类似常量。

导入所有值

风格指南有时会推荐显式导入模块将用到的所有符号。不过在从定义了很多导出的模块导入值时,可以像下面这样以一条 import 语句轻松地导入所有值

javascript
import * as stats from "./stats.js";

像这样一条import语句可以创建一个对象,并将其赋值给一个名为stats的常量。被导入模块的每个非默认导出都会变成这个stats对象的一个属性。非默认导出始终有名字,这些名字将作为这个对象的属性名。这些属性是常量,不能被重写或删除在使用前面这个带通配符的导入语句时,导入模块需要通过stats对象使用导入的 mean()stddev() 函数,即要通过 stats.mean()stats.stddev() 调用它们。

混合导入

模块通常要么定义一个默认导出,要么定义多个命名导出。一个模块同时使用 export 和 export default 虽然合法,但并不常见。不过要是真有模块这么做,也可以只通过一条import语句同时导入默认值和命名值

javascript
import Histogram, { mean, stddev } from "./histogram-stats.js";

前面我们介绍了如何从带有默认导出的模块导入,以及如何从带有非默认导出或已命名导出的模块导入。而 import 语句还有另一种形式,用于导入没有任何导出的模块。要在程序中包含没有导出的模块,只要在import关键字后面直接写出模块标识符即可

导入时执行
javascript
import './analytics.js*';

这样的模块会在被首次导入时运行一次(之后再导入时则什么也不做)。如果模块中只定义了一些函数,那么它至少要导出其中一个函数才能有用。而如果模块中运行一些代码,那么即便没有符号导入也会很有用。Web应用可以使用分析模块(如analytics.js) 运行注册各种事件处理程序的代码,然后通过这些事件处理程序在合适的时机向服务器发送遥测数据。虽然模块是自包含的,不需要导出任何值,但仍然需要通过import导入才能让它作为程序的一部分运行。

注意,对那些有导出的模块也可以使用这种什么也不导入的import语法。如果模块定义了与它的导出值无关的有用行为,而你的程序不需要它的任何导出值,那么可以只为它的默认行为导入这个模块。

导入和导出时重命名

如果两个模块使用相同的名字导出了两个不同的值,而你希望同时导入这两个值,那必须在导入时对其中一个或这两个进行重命名。类似地,如果在导入某个值时发现它的名字已经被占用了,则需要重命名这个导入值。可以在命名导入时使用as关键字对导入值进行重命名

javascript
import ( render as renderImage } from "./imageutils.js"; 
import ( render as renderUI } from "./ui.js";

这两行代码向当前模块导入了两个函数。这两个函数在定义它们的模块中都被命名为 render(),但在导入时被重命名为更好理解且没有歧义的renderImage()renderUI()

我们知道默认导出没有名字。导入模块在导入默认导出时始终需要选择一个名字。因此这种情况下不需要特殊语法。

尽管如此,导入时重命名的机制也为同时定义了默认导出和命名导出的模块提供了另一种导入方式。上一节的示例中有一个"./histogram-stats.js”模块,下面是同时导入其默认导出和命名导出的另一种方式

javascript
import { default as Histogram, mean, stddev } from /histogram-stats,js*';

在这种情况下,JavaScript关键字default充当一个占位符,允许我们指明想导入模块的默认导出并为其提供一个名字。

导出值时也可以重命名,但仅限于使用export语句的花括号形式。通常并不需要这样做,但如果你在模块内部使用了简洁短小的名字,那在导出值时可能希望使用更有描述性同时也不容易与其他模块冲突的名字。与导入时重命名类似,导出时重命名也要使用as关键字

javascript
export {
  layout as calculateLayout, 
  render as renderLayout
};

请大家始终记住,虽然这里的花括号看起来像对象字面量,但其实并不是。而且,export 关键字需要 as 前面是一个标识符,而非表达式。这意味着不能像下面这样在导出时重命名

javascript
export { Math.sin as sin, Math.cos as cos ); // SyntaxError

再导出

通过import()动态导入

import.meta.url

小结

模块化的目标是让程序员隐藏自己代码的实现细节,从而让不同来源的代码块可以组装成一个大型程序,又不必担心某个代码块会重写其他代码块的函数或变量。本章解释了三种不同的JavaScript模块系统

  • 在 JavaScript 早期,模块化只能通过巧妙地使用立即调用的函数表达式来实现。
  • Node 在 JavaScript 语言之上加入了自己的模块系统。Node 模块通过 require()导入,并通过设置 Exports 对象的属性或直接设置 module.exports 属性来定义导出。
  • 在 ES6 中,JavaScript 终于有了自己依托 import 和 export 关键字的模块系统,ES2020 又通过 import()增加了对动态导入的支持。

在模块之外,包和NPM则是将模块联系起来的一种机制。

在介绍NPM之前,不得不提起CommonJS的包规范。JavaScript不似Java或者其他语言那样,具有模块和包结构。Node对模块规范的实现,一定程度上解决了变量依赖、依赖关系等代码组织性问题。包的出现,则是在模块的基础上进一步组织JavaScript代码。

包结构

包实际上是一个存档文件,即一个日录直接打包为.zip.tar.gz格式的文件,安装后解压还原为目录。完全符合CommonJS规范的包目录应该包含如下这些文件。

  • package.json: 包描述文件。
  • bin: 用于存放可执行二进制文件的目录。
  • lib: 用于存放JavaScript代码的目录。
  • doc: 用于存放文档的目录。
  • test: 用于存放单元测试用例的代码。

包描述文件

  • type: 定义package.json文件和该文件所在目录根目录中.js文件和无拓展名文件的处理方式。
    • 值为module则当作es模块处理;
    • 值为commonjs则被当作CommonJS模块处理【 默认值 】;
    • 无论type字段为何值,.mjs的文件都按照es模块处理,.cjs的文件都按照CommonJS模块处理。
  • dependencies: 使用当前包所需要依赖的包列表
  • devDependencies。一些模块只在开发时需要依赖。配置这个属性,可以提示包的后续开发者安装依赖包。
  • scripts: 脚本说明对象。它主要被包管理器用来安装、编译、测试和卸载包。示例如下:
    js
    "scripts": {
      "install": "install.js", 
      "uninstall": "uninstall.js", 
      "build": "build.js",
      "doc": "make-doc.js',
      "test": "test.js",
    }
  • name: 包名
  • description: 包简介
  • version: 版本号
  • keywords: 关键词数组,NPM中主要用来做分类搜素
  • maintainers: 包维护者列表
  • contributors: 贡献者列表
  • bugs: 一个可以反馈bug的网页地址或邮件地址
  • licenses: 当前包所使用的许可证列表,表示这个包可以在哪些许可证下使用
  • repositories: 托管源代码的位置列表,表明可以通过哪些方式和地址访问包的源代码
  • homepage: 当前包的网站地址
  • os: 操作系统支持列表
  • cpu: CPU架构的支持列表
  • engine: 支持的JavaScript引擎列表,有效的引擎取值包括ejs、flusspferd、gpsee、jsc、spidermonkey、narwhal、node和v8
  • builtin: 标志当前包是否是内建在底层系统的标准组件
  • directories: 包目录说明
  • implements: 实现规范的列表。标志当前包实现了CommonJS的哪些规范
  • author: 包作者
  • bin: 一些包作者希望包可以作为命令行工具使用。配置好bin字段后,通过npm install package-name -g命令可以將脚本添加到执行路径中,之后可以在命令行中直接执行。
  • main: 模块引入方法 require 在引入包时,会优先检查这个字段,并将其作为包中其余模块的入口。如果不存在这个字段,require()方法会查找包目录下的index.jsindex.nodeindex.json文件作为默认入口

Node.js 包管理器

  • npm: Node.js的包管理器,用于安装和管理Node.js模块。
  • npx: Node.js 8.2.0 版本引入的新工具,用于快速执行包中的命令。
  • yarn: Facebook开发的另一个包管理器,具有更快的安装速度和更好的可重用性,同时提供离线缓存等功能。
  • pnpm: 一个快速、轻量级的包管理器,与npm和yarn不同,它使用单一的存储库来避免重复的包下载,节约磁盘空间。

两种包类型

  • 全局安装

    安装时要添加-g参数或--global参数

    全局安装

    安装结束之后,直接在控制台就可以使用的一种包

    比如以前装的cnpmvue

  • 局部安装

    基于某个项目安装

    axios、mitt、tiny-emitter...

    基于当前项目安装,只有在当前项目中使用的一种

    局部安装也分为两种: dependencies、devDependencies

    dependencies无论在开发环境还是生产环境都需要使用

    devDependencies只在开发环境中才使用

npm(Node Package Manager)

Nodejs自带的、原生的包管理器

yarn

Resource Manager

在pnpm和npx没有出现以前,几乎所有的主流node项目所推荐使用的包管理器

yarn与npm的对比
---
初始化node项目yarn initnpm init
局部安装yarn add axiosnpm install axios
删除包yarn removenpm uninstall
基于package.json更新包yarn install【可简写为yarnnpm install
yarn安装

采用npm全局安装

bash
npm i yarn -g
yarn配置淘宝镜像源
bash
yarn config set registry=https://registry.npm.taobao.org
yarn基于package.json构建node_modules目录
bash
yarn
yarn在当前项目中添加一个axios包
bash
yarn add axios
yarn更新当前项目中的所有包
bash
yarn upgrade

Node.js核心模块

fs模块

本质上就是java中的io流

字符输入流

js
import fs from 'fs'

fs.readFile('package.json', 'utf-8', function(err, data) {
    if (err) {
        console.log(err);
    } else {
        console.log(data);
    }
})

字节输入流

js
import fs from 'fs'

let buf = Buffer.alloc(1024)

fs.open('package.json', 'r+', function(err, fd) {
    if(err){
        return console.log(err)
    }

    fs.read(fd, buf, function(err,bytes) {
        if(err){
            return console.log(err)
        }

        if (bytes > 0) {
            console.log(buf.slice(0, bytes).toString())
        }
    })
})

fs处理大文件

因为默认情况下,fs中的文件操作函数是异步方式,当操作结束之后,通过回调函数通知

但操作大文件时,无法一次性读完,或者写完一个文件,此时就必须使用fs的同步方式操作文件

既第一次读完以后,再读第二次

或第一次写完以后,再写第二次

js
import fs from 'fs'

const buf = Buffer.alloc(4)

fs.open("package.json", "r+", function (err, fd) {

    while (true) {
        let len = fs.readSync(fd, buf);
        console.log(buf.slice(0, len).toString());

        if (len != buf.length) {
            break;
        }
    }
})

字符输出流

js
import fs from 'fs'

fs.writeFile("output.txt", "Hello", function (err) {
    if (err) {
        console.log(err);
    }
})

字节输出流

js
import fs from 'fs'

const buf = Buffer.alloc(4)

// 目标文件
fs.open("newpackage.json", 'w+', function(werr, wfd) {

    // 源文件
    fs.open("package.json", 'r+', function(rerr, rfd) {

        while (true) {
            let len = fs.readSync(rfd, buf);

            fs.writeSync(wfd, buf, 0, len);

            if (len != buf.length) {
                break;
            }
        }
    })
})

path模块

js
// 引入 Path 模块
// const path = require('path');
import path from 'path'

// 获取文件路径信息
const filePath = '/path/to/your/file.txt';
console.log('文件路径:', filePath);
console.log('文件名:', path.basename(filePath));
console.log('目录名:', path.dirname(filePath));
console.log('文件后缀名:', path.extname(filePath));

// 拼接路径
const dirPath = '/path/to/your';
const fileName = 'file.txt';
console.log('拼接后的路径:', path.join(dirPath, fileName));

// 解析路径
const absolutePath = '/path/to/your';
console.log('绝对路径:', absolutePath);
console.log('解析后的路径:', path.resolve(absolutePath, '../anotherfile.txt'));

os模块

js
// 引入 OS 模块
// const os = require('os');
import os from 'os';

// 获取操作系统相关信息
console.log('主机名:', os.hostname());
console.log('操作系统类型:', os.type());
console.log('操作系统平台:', os.platform());
console.log('操作系统架构:', os.arch());
console.log('操作系统版本:', os.release());

// 获取内存信息
console.log('总内存量:', os.totalmem() / (1024 * 1024 * 1024), 'GB');
console.log('空闲内存量:', os.freemem() / (1024 * 1024 * 1024), 'GB');

// 获取 CPU 信息
console.log('CPU 核心数量:', os.cpus().length);
console.log('CPU 信息:', os.cpus());

url模块

js
// 引入 URL 模块
// const url = require('url');
import url from 'url';

// 解析 URL
const urlString = 'https://www.example.com:8080/path/to/page?query=string#hash';
const parsedUrl = url.parse(urlString, true);
console.log('解析后的 URL 对象:', parsedUrl);
console.log('协议:', parsedUrl.protocol);
console.log('主机名:', parsedUrl.hostname);
console.log('端口号:', parsedUrl.port);
console.log('路径:', parsedUrl.pathname);
console.log('查询字符串:', parsedUrl.query);
console.log('哈希:', parsedUrl.hash);

// 构建 URL
const constructedUrl = url.format({
  protocol: 'https',
  hostname: 'www.example.com',
  port: 8080,
  pathname: '/path/to/page',
  query: { query: 'string' },
  hash: '#hash'
});
console.log('构建后的 URL:', constructedUrl);

http模块

js
import http from 'http'

http.createServer((req, res) => {
    res.writeHead(200, {"Content-Type": 'text/html; charset=utf-8'})
    res.write("<h1>Hello Node.js</h1>")
    res.end("<p>Hello World!</p>")
}).listen(3000);

console.log("Nodejs http服务器已经启动")