【node.js】入门基础

个人主页:Guiat
归属专栏:node.js

文章目录

  • [1. Node.js简介](#1. Node.js简介)
    • [1.1 Node.js的核心特点](#1.1 Node.js的核心特点)
    • [1.2 Node.js适用场景](#1.2 Node.js适用场景)
  • [2. 第一个Node.js程序](#2. 第一个Node.js程序)
    • [2.1 创建并运行Hello World](#2.1 创建并运行Hello World)
    • [2.2 创建简单的HTTP服务器](#2.2 创建简单的HTTP服务器)
  • [3. Node.js核心概念](#3. Node.js核心概念)
    • [3.1 模块系统](#3.1 模块系统)
      • [3.1.1 创建和导出模块](#3.1.1 创建和导出模块)
      • [3.1.2 导入和使用模块](#3.1.2 导入和使用模块)
      • [3.1.3 ES模块语法(ES Modules)](#3.1.3 ES模块语法(ES Modules))
    • [3.2 事件循环](#3.2 事件循环)
      • [3.2.1 事件循环示例](#3.2.1 事件循环示例)
      • [3.2.2 异步文件操作示例](#3.2.2 异步文件操作示例)
    • [3.3 事件发射器 (EventEmitter)](#3.3 事件发射器 (EventEmitter))
      • [3.3.1 自定义事件发射器](#3.3.1 自定义事件发射器)
    • [3.4 流 (Streams)](#3.4 流 (Streams))
      • [3.4.1 流的类型](#3.4.1 流的类型)
      • [3.4.2 文件流示例](#3.4.2 文件流示例)
      • [3.4.3 使用pipe()简化流操作](#3.4.3 使用pipe()简化流操作)
      • [3.4.4 创建自定义流](#3.4.4 创建自定义流)
  • [4. 文件系统操作](#4. 文件系统操作)
    • [4.1 同步与异步文件操作](#4.1 同步与异步文件操作)
    • [4.2 写入文件](#4.2 写入文件)
    • [4.3 目录操作](#4.3 目录操作)
    • [4.4 文件路径操作](#4.4 文件路径操作)
  • [5. HTTP服务器开发](#5. HTTP服务器开发)
    • [5.1 创建基本HTTP服务器](#5.1 创建基本HTTP服务器)
    • [5.2 处理HTTP请求和路由](#5.2 处理HTTP请求和路由)
    • [5.3 处理静态文件](#5.3 处理静态文件)

正文

1. Node.js简介

Node.js是一个开源、跨平台的JavaScript运行环境,它允许开发者使用JavaScript来编写服务器端代码。Node.js采用Google Chrome的V8引擎来执行JavaScript代码,具有非阻塞I/O和事件驱动机制,使其成为构建高性能网络应用的理想选择。

1.1 Node.js的核心特点

Node.js核心特点 非阻塞I/O 事件驱动 单线程 跨平台 npm生态系统

  • 非阻塞I/O:执行I/O操作时不会阻塞线程
  • 事件驱动:基于事件循环处理并发操作
  • 单线程:使用单线程处理多个并发连接
  • 跨平台:可在Windows、macOS和Linux等多种操作系统上运行
  • npm:拥有世界上最大的开源代码库生态系统

1.2 Node.js适用场景

Node.js特别适合以下场景:

  • 实时应用(聊天、游戏服务器)
  • REST API和微服务
  • 单页面应用(SPA)的后端
  • 流处理和数据密集型应用
  • 命令行工具

2. 第一个Node.js程序

2.1 创建并运行Hello World

创建一个名为hello.js的文件,内容如下:

javascript 复制代码
// 第一个Node.js程序
console.log("Hello, Node.js!");

在命令行中运行:

bash 复制代码
node hello.js

输出结果:

复制代码
Hello, Node.js!

2.2 创建简单的HTTP服务器

创建一个基本的Web服务器:

javascript 复制代码
// 创建简单的HTTP服务器
const http = require('http');

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 设置响应头
  res.writeHead(200, {'Content-Type': 'text/plain'});
  
  // 发送响应数据
  res.end('Hello World from Node.js Server!');
});

// 服务器监听3000端口
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});

运行服务器:

bash 复制代码
node server.js

现在可以在浏览器中访问http://localhost:3000查看结果。

3. Node.js核心概念

3.1 模块系统

Node.js使用CommonJS模块系统,允许将代码分割成可重用的部分。

3.1.1 创建和导出模块

javascript 复制代码
// math.js - 创建一个数学工具模块
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

function multiply(a, b) {
  return a * b;
}

function divide(a, b) {
  if (b === 0) {
    throw new Error('Cannot divide by zero');
  }
  return a / b;
}

// 导出多个函数
module.exports = {
  add,
  subtract,
  multiply,
  divide
};

3.1.2 导入和使用模块

javascript 复制代码
// app.js - 使用数学工具模块
const math = require('./math');

console.log(`2 + 3 = ${math.add(2, 3)}`);
console.log(`5 - 2 = ${math.subtract(5, 2)}`);
console.log(`4 * 6 = ${math.multiply(4, 6)}`);
console.log(`10 / 2 = ${math.divide(10, 2)}`);

// 也可以使用解构赋值
const { add, multiply } = require('./math');
console.log(`4 + 5 = ${add(4, 5)}`);
console.log(`3 * 7 = ${multiply(3, 7)}`);

3.1.3 ES模块语法(ES Modules)

Node.js也支持ES模块语法,需要将文件后缀改为.mjs或在package.json中设置"type": "module"

javascript 复制代码
// mathES.mjs - ES模块语法
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

// 导出默认值
export default {
  name: 'Math Utils',
  version: '1.0.0'
};
javascript 复制代码
// appES.mjs - 导入ES模块
import { add, subtract } from './mathES.mjs';
import mathInfo from './mathES.mjs';

console.log(`ES模块: 2 + 3 = ${add(2, 3)}`);
console.log(`模块信息: ${mathInfo.name} v${mathInfo.version}`);

3.2 事件循环

Node.js的事件循环是其非阻塞I/O模型的核心,它允许Node.js执行非阻塞操作。
事件循环 定时器阶段 待定回调阶段 idle/prepare阶段 轮询阶段 检查阶段 关闭回调阶段

3.2.1 事件循环示例

javascript 复制代码
console.log('1. 开始执行');

// 延迟执行 (宏任务)
setTimeout(() => {
  console.log('4. setTimeout 回调执行');
}, 0);

// Promise (微任务)
Promise.resolve().then(() => {
  console.log('3. Promise 回调执行');
});

console.log('2. 结束执行');

// 输出顺序:
// 1. 开始执行
// 2. 结束执行
// 3. Promise 回调执行
// 4. setTimeout 回调执行

3.2.2 异步文件操作示例

javascript 复制代码
const fs = require('fs');

console.log('1. 开始读取文件');

// 异步读取文件
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('读取文件出错:', err);
    return;
  }
  console.log('3. 文件内容:', data);
});

console.log('2. 读取文件的请求已发出,继续执行其他操作');

3.3 事件发射器 (EventEmitter)

EventEmitter是Node.js的核心模块,用于实现事件驱动架构。

javascript 复制代码
const EventEmitter = require('events');

// 创建事件发射器实例
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

// 注册事件监听器
myEmitter.on('event', (a, b) => {
  console.log('事件发生了!', a, b);
});

// 注册只执行一次的事件监听器
myEmitter.once('onceEvent', () => {
  console.log('这个事件只会触发一次');
});

// 触发事件
myEmitter.emit('event', 'a', 'b');
myEmitter.emit('onceEvent');
myEmitter.emit('onceEvent'); // 这次不会触发监听器

3.3.1 自定义事件发射器

javascript 复制代码
const EventEmitter = require('events');

// 创建一个用户类,继承EventEmitter
class User extends EventEmitter {
  constructor(name) {
    super();
    this.name = name;
  }
  
  sayHello() {
    console.log(`${this.name} says hello!`);
    // 触发事件
    this.emit('hello', this.name);
  }
  
  sayGoodbye() {
    console.log(`${this.name} says goodbye!`);
    // 触发事件
    this.emit('goodbye', this.name);
  }
}

// 创建用户实例
const user = new User('John');

// 添加事件监听器
user.on('hello', (name) => {
  console.log(`Hello event was triggered by ${name}`);
});

user.on('goodbye', (name) => {
  console.log(`Goodbye event was triggered by ${name}`);
});

// 调用方法,触发事件
user.sayHello();
user.sayGoodbye();

3.4 流 (Streams)

流是用于处理读写数据的抽象接口,尤其适合处理大文件。

3.4.1 流的类型

  • 可读流 (Readable):用于读取数据
  • 可写流 (Writable):用于写入数据
  • 双工流 (Duplex):可读可写
  • 转换流 (Transform):在读写过程中修改数据

3.4.2 文件流示例

javascript 复制代码
const fs = require('fs');

// 创建可读流
const readStream = fs.createReadStream('source.txt', 'utf8');

// 创建可写流
const writeStream = fs.createWriteStream('destination.txt');

// 处理流事件
readStream.on('data', (chunk) => {
  console.log(`接收到 ${chunk.length} 字节的数据`);
  // 写入数据到可写流
  writeStream.write(chunk);
});

readStream.on('end', () => {
  writeStream.end(); // 结束写入流
  console.log('读取完成');
});

readStream.on('error', (err) => {
  console.error('读取错误:', err);
});

writeStream.on('finish', () => {
  console.log('写入完成');
});

writeStream.on('error', (err) => {
  console.error('写入错误:', err);
});

3.4.3 使用pipe()简化流操作

javascript 复制代码
const fs = require('fs');

// 创建可读流和可写流
const readStream = fs.createReadStream('source.txt');
const writeStream = fs.createWriteStream('destination.txt');

// 使用pipe直接将可读流连接到可写流
readStream.pipe(writeStream);

// 处理事件
readStream.on('end', () => {
  console.log('读取完成');
});

writeStream.on('finish', () => {
  console.log('写入完成');
});

3.4.4 创建自定义流

javascript 复制代码
const { Transform } = require('stream');

// 创建转换流,将文本转为大写
class UppercaseTransform extends Transform {
  _transform(chunk, encoding, callback) {
    // 转换数据
    const upperChunk = chunk.toString().toUpperCase();
    // 推送转换后的数据
    this.push(upperChunk);
    // 调用回调,表示处理完成
    callback();
  }
}

// 使用自定义转换流
const upperCaseStream = new UppercaseTransform();

// 从标准输入读取,经过转换后写入标准输出
process.stdin
  .pipe(upperCaseStream)
  .pipe(process.stdout);

4. 文件系统操作

Node.js提供了fs模块用于与文件系统交互。

4.1 同步与异步文件操作

javascript 复制代码
const fs = require('fs');

// 同步读取文件(阻塞)
try {
  const data = fs.readFileSync('file.txt', 'utf8');
  console.log('同步读取文件:', data);
} catch (err) {
  console.error('同步读取错误:', err);
}

// 异步读取文件(非阻塞)
fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('异步读取错误:', err);
    return;
  }
  console.log('异步读取文件:', data);
});

// 使用Promise API (Node.js 10+)
fs.promises.readFile('file.txt', 'utf8')
  .then(data => {
    console.log('Promise读取文件:', data);
  })
  .catch(err => {
    console.error('Promise读取错误:', err);
  });

// 使用async/await (Node.js 10+)
async function readFileAsync() {
  try {
    const data = await fs.promises.readFile('file.txt', 'utf8');
    console.log('Async/Await读取文件:', data);
  } catch (err) {
    console.error('Async/Await读取错误:', err);
  }
}

readFileAsync();

4.2 写入文件

javascript 复制代码
const fs = require('fs');

// 同步写入
try {
  fs.writeFileSync('output1.txt', 'Hello, Node.js! (同步写入)', 'utf8');
  console.log('同步写入完成');
} catch (err) {
  console.error('同步写入错误:', err);
}

// 异步写入
fs.writeFile('output2.txt', 'Hello, Node.js! (异步写入)', 'utf8', (err) => {
  if (err) {
    console.error('异步写入错误:', err);
    return;
  }
  console.log('异步写入完成');
});

// 追加内容到文件
fs.appendFile('output2.txt', '\n这是追加的内容', 'utf8', (err) => {
  if (err) {
    console.error('追加错误:', err);
    return;
  }
  console.log('追加完成');
});

4.3 目录操作

javascript 复制代码
const fs = require('fs');
const path = require('path');

// 创建目录
fs.mkdir('new-directory', (err) => {
  if (err) {
    console.error('创建目录错误:', err);
    return;
  }
  console.log('目录创建成功');
});

// 递归创建多级目录
fs.mkdir('parent/child/grandchild', { recursive: true }, (err) => {
  if (err) {
    console.error('创建多级目录错误:', err);
    return;
  }
  console.log('多级目录创建成功');
});

// 读取目录内容
fs.readdir('.', (err, files) => {
  if (err) {
    console.error('读取目录错误:', err);
    return;
  }
  console.log('当前目录文件:');
  files.forEach(file => {
    console.log(`- ${file}`);
  });
});

// 获取文件信息
fs.stat('file.txt', (err, stats) => {
  if (err) {
    console.error('获取文件信息错误:', err);
    return;
  }
  console.log('文件信息:');
  console.log(`- 是文件? ${stats.isFile()}`);
  console.log(`- 是目录? ${stats.isDirectory()}`);
  console.log(`- 文件大小: ${stats.size} 字节`);
  console.log(`- 创建时间: ${stats.birthtime}`);
  console.log(`- 修改时间: ${stats.mtime}`);
});

4.4 文件路径操作

javascript 复制代码
const path = require('path');

// 路径拼接 (跨平台兼容)
const fullPath = path.join(__dirname, 'subfolder', 'file.txt');
console.log('拼接路径:', fullPath);

// 解析路径
const pathInfo = path.parse('/home/user/documents/file.txt');
console.log('路径信息:', pathInfo);
/*
输出:
{
  root: '/',
  dir: '/home/user/documents',
  base: 'file.txt',
  ext: '.txt',
  name: 'file'
}
*/

// 规范化路径
console.log('规范化路径:', path.normalize('/home//user/../user/docs/'));
// 输出: /home/user/docs/

// 获取绝对路径
console.log('绝对路径:', path.resolve('subfolder', 'file.txt'));

// 获取扩展名
console.log('扩展名:', path.extname('file.txt')); // 输出: .txt

5. HTTP服务器开发

5.1 创建基本HTTP服务器

javascript 复制代码
const http = require('http');

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 获取请求信息
  const { method, url, headers } = req;
  console.log(`收到 ${method} 请求: ${url}`);
  
  // 根据URL路径提供不同响应
  if (url === '/') {
    // 设置响应头
    res.writeHead(200, {'Content-Type': 'text/html'});
    // 发送响应数据
    res.end(`
      <html>
        <head><title>Node.js服务器</title></head>
        <body>
          <h1>欢迎来到Node.js服务器!</h1>
          <p>当前时间: ${new Date().toLocaleString()}</p>
          <ul>
            <li><a href="/about">关于我们</a></li>
            <li><a href="/contact">联系我们</a></li>
          </ul>
        </body>
      </html>
    `);
  } 
  else if (url === '/about') {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(`
      <html>
        <head><title>关于我们</title></head>
        <body>
          <h1>关于我们</h1>
          <p>这是一个简单的Node.js HTTP服务器示例。</p>
          <a href="/">返回首页</a>
        </body>
      </html>
    `);
  }
  else if (url === '/contact') {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(`
      <html>
        <head><title>联系我们</title></head>
        <body>
          <h1>联系我们</h1>
          <p>Email: example@example.com</p>
          <a href="/">返回首页</a>
        </body>
      </html>
    `);
  }
  else if (url === '/api/time') {
    // 返回JSON数据
    res.writeHead(200, {'Content-Type': 'application/json'});
    res.end(JSON.stringify({
      time: new Date().toISOString(),
      timestamp: Date.now()
    }));
  }
  else {
    // 404 Not Found
    res.writeHead(404, {'Content-Type': 'text/html'});
    res.end(`
      <html>
        <head><title>404 Not Found</title></head>
        <body>
          <h1>404 - 页面不存在</h1>
          <p>请求的URL "${url}" 不存在</p>
          <a href="/">返回首页</a>
        </body>
      </html>
    `);
  }
});

// 服务器监听端口
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}/`);
});

5.2 处理HTTP请求和路由

javascript 复制代码
const http = require('http');
const url = require('url');

// 路由处理函数
const routes = {
  'GET': {
    '/': (req, res) => {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.end('<h1>首页</h1><p>欢迎访问我们的网站</p>');
    },
    '/about': (req, res) => {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.end('<h1>关于我们</h1><p>这是关于页面</p>');
    },
    '/api/users': (req, res) => {
      const users = [
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' },
        { id: 3, name: 'Charlie' }
      ];
      res.writeHead(200, {'Content-Type': 'application/json'});
      res.end(JSON.stringify(users));
    }
  },
  'POST': {
    '/api/users': (req, res) => {
      let body = '';
      
      // 收集请求体数据
      req.on('data', chunk => {
        body += chunk.toString();
      });
      
      // 请求体接收完毕
      req.on('end', () => {
        try {
          const userData = JSON.parse(body);
          // 处理用户数据...
          res.writeHead(201, {'Content-Type': 'application/json'});
          res.end(JSON.stringify({
            message: '用户创建成功',
            user: userData
          }));
        } catch (error) {
          res.writeHead(400, {'Content-Type': 'application/json'});
          res.end(JSON.stringify({
            error: '无效的JSON数据'
          }));
        }
      });
    }
  }
};

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 解析URL和查询参数
  const parsedUrl = url.parse(req.url, true);
  const path = parsedUrl.pathname;
  const method = req.method.toUpperCase();
  const query = parsedUrl.query;
  
  console.log(`${method} ${path}`);
  
  // 查找路由处理函数
  const routeHandler = routes[method] && routes[method][path];
  
  if (routeHandler) {
    // 将查询参数附加到请求对象
    req.query = query;
    // 调用路由处理函数
    routeHandler(req, res);
  } else {
    // 未找到路由处理函数,返回404
    res.writeHead(404, {'Content-Type': 'text/html'});
    res.end('<h1>404 - 页面不存在</h1>');
  }
});

// 启动服务器
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}/`);
});

5.3 处理静态文件

javascript 复制代码
const http = require('http');
const fs = require('fs');
const path = require('path');

// 静态文件目录
const PUBLIC_DIR = path.join(__dirname, 'public');

// MIME类型映射
const MIME_TYPES = {
  '.html': 'text/html',
  '.css': 'text/css',
  '.js': 'text/javascript',
  '.json': 'application/json',
  '.png': 'image/png',
  '.jpg': 'image/jpeg',
  '.jpeg': 'image/jpeg',
  '.gif': 'image/gif',
  '.svg': 'image/svg+xml',
  '.ico': 'image/x-icon',
  '.txt': 'text/plain'
};

// 创建HTTP服务器
const server = http.createServer((req, res) => {
  // 仅处理GET请求
  if (req.method !== 'GET') {
    res.writeHead(405, {'Content-Type': 'text/plain'});
    res.end('Method Not Allowed');
    return;
  }
  
  // 获取请求路径
  let filePath = path.join(PUBLIC_DIR, req.url === '/' ? 'index.html' : req.url);
  
  // 检查文件是否存在
  fs.stat(filePath, (err, stats) => {
    if (err) {
      // 文件不存在,返回404
      res.writeHead(404, {'Content-Type': 'text/html'});
      res.end('<h1>404 - 文件未找到</h1>');
      return;
    }
    
    // 如果是目录,尝试加载index.html
    if (stats.isDirectory()) {
      filePath = path.join(filePath, 'index.html');
    }
    
    // 获取文件扩展名
    const extname = path.extname(filePath);
    
    // 获取MIME类型
    const contentType = MIME_TYPES[extname] || 'application/octet-stream';
    
    // 读取并发送文件
    fs.readFile(filePath, (err, content) => {
      if (err) {
        if (err.code === 'ENOENT') {
          // 文件不存在
          res.writeHead(404, {'Content-Type': 'text/html'});
          res.end('<h1>404 - 文件未找到</h1>');
        } else {
          // 服务器错误
          res.writeHead(500, {'Content-Type': 'text/html'});
          res.end('<h1>500 - 服务器错误</h1>');
        }
      } else {
        // 发送文件
        res.writeHead(200, {'Content-Type': contentType});
        res.end(content);
      }
    });
  });
});

// 启动服务器
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`静态文件服务器运行在 http://localhost:${PORT}/`);
  console.log(`提供目录: ${PUBLIC_DIR}`);
});

结语

感谢您的阅读!期待您的一键三连!欢迎指正!

相关推荐
@PHARAOH19 小时前
WHAT - npm和corepack
前端·npm·node.js
MPGWJPMTJT19 小时前
从 Volta 迁移到 mise:Windows 下 Node 版本管理切换记录
前端·node.js
zhangfeng113319 小时前
Remotion 渲染视频脚本 ,自动化编辑视频 Node.js 层面是“单线程 JS”,但在实际渲染时是“高度并行”的。
node.js·自动化·音视频
羽师20 小时前
Node.js和npx关系
node.js
灵魂学者20 小时前
使用 Electron 打包项目构建 .EXE 桌面应用程序(简)
electron·node.js·vue·build·桌面应用程序
右耳朵猫AI20 小时前
Node.js技术周刊 2026年第14周
node.js
gogoing1 天前
Node.js 模块查找策略(require 完整流程)
javascript·node.js
zhangfeng11331 天前
小龙虾 wordbuddy 安装浏览器控制器 agent-browser npm install -g agent-browse
前端·人工智能·npm·node.js
大家的林语冰2 天前
pnpm 11 发布,弃用 JSON 和 npm CLI,进化为纯 ES6 模块,新增 pnpm pack-app 等命令,供应链保护默认启用,要求 Node
前端·javascript·node.js
会周易的程序员2 天前
aiDgeScanner 工业设备网络扫描与管理工具
网络·c++·物联网·架构·electron·node.js·iot