文章目录
正文
1. Node.js简介
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它使JavaScript可以在服务器端运行。Node.js采用事件驱动、非阻塞I/O模型,使其轻量且高效,非常适合构建数据密集型的实时应用程序。
1.1 Node.js的特点
- 单线程、事件驱动
- 非阻塞I/O模型
- 跨平台(Windows、macOS、Linux)
- 强大的包管理系统(npm)
- 高性能处理并发连接
1.2 Node.js架构
2. Node.js安装
2.1 下载和安装方法
Node.js有多种安装方式,针对不同操作系统:
2.1.1 Windows安装
# 使用Chocolatey包管理器安装
choco install nodejs
# 或使用WinGet安装
winget install OpenJS.NodeJS
2.1.2 macOS安装
# 使用Homebrew安装
brew install node
# 也可使用MacPorts
port install nodejs
2.1.3 Linux安装
# Ubuntu/Debian系统
sudo apt update
sudo apt install nodejs npm
# RHEL/CentOS/Fedora系统
sudo dnf install nodejs
# Arch Linux
sudo pacman -S nodejs npm
2.2 使用NVM安装和管理Node.js版本
Node Version Manager (NVM)是一个流行的Node.js版本管理工具,可以方便地安装和切换不同版本的Node.js。
2.2.1 安装NVM
# macOS/Linux安装NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
# 或者使用wget
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
# Windows可使用nvm-windows
# 下载安装包: https://github.com/coreybutler/nvm-windows/releases
2.2.2 使用NVM管理Node.js
# 查看可用的Node.js版本
nvm ls-remote
# 安装特定版本的Node.js
nvm install 16.14.0
# 安装最新LTS版本
nvm install --lts
# 切换Node.js版本
nvm use 14.17.0
# 设置默认Node.js版本
nvm alias default 16.14.0
# 查看已安装的版本
nvm ls
2.3 验证安装
安装完成后,可以通过以下命令验证Node.js和npm是否安装成功:
# 检查Node.js版本
node -v
# 检查npm版本
npm -v
# 运行简单的JavaScript代码
node -e "console.log('Hello, Node.js!')"
3. Node.js环境配置
3.1 npm配置
npm(Node Package Manager)是Node.js默认的包管理工具,可以进行各种配置以优化开发体验。
3.1.1 基础npm配置
# 查看当前npm配置
npm config list
# 设置npm镜像源为淘宝镜像(国内加速)
npm config set registry https://registry.npmmirror.com
# 设置全局安装路径
npm config set prefix /path/to/global/node_modules
# 设置缓存路径
npm config set cache /path/to/npm/cache
# 设置代理(如果需要)
npm config set proxy http://proxy.example.com:8080
npm config set https-proxy http://proxy.example.com:8080
3.1.2 创建.npmrc文件
可以在项目根目录或用户主目录创建.npmrc文件进行配置:
# ~/.npmrc或项目目录/.npmrc
registry=https://registry.npmmirror.com
save-exact=true
fund=false
audit=false
3.2 package.json配置
package.json是Node.js项目的配置文件,包含项目依赖、脚本等信息。
3.2.1 创建package.json
# 交互式创建package.json
npm init
# 创建默认package.json
npm init -y
3.2.2 package.json示例
{
"name": "my-node-app",
"version": "1.0.0",
"description": "A sample Node.js application",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest",
"lint": "eslint ."
},
"keywords": ["node", "example"],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"express": "^4.18.2",
"dotenv": "^16.0.3",
"mongoose": "^7.0.0"
},
"devDependencies": {
"nodemon": "^2.0.22",
"jest": "^29.5.0",
"eslint": "^8.36.0"
},
"engines": {
"node": ">=14.0.0"
}
}
3.3 环境变量配置
3.3.1 使用dotenv管理环境变量
# 安装dotenv包
npm install dotenv
创建.env文件:
# .env文件
PORT=3000
NODE_ENV=development
DATABASE_URL=mongodb://localhost:27017/myapp
API_KEY=your_secret_api_key
在代码中使用:
// 在应用入口处尽早加载
require('dotenv').config();
// 使用环境变量
const port = process.env.PORT || 3000;
console.log(`Server running on port ${port}`);
3.3.2 不同环境的配置
可以为不同环境创建多个环境配置文件:
.env # 默认环境
.env.development # 开发环境
.env.test # 测试环境
.env.production # 生产环境
加载特定环境配置:
// 加载特定环境配置
require('dotenv').config({ path: `.env.${process.env.NODE_ENV || 'development'}` });
3.4 调试配置
3.4.1 使用内置调试器
Node.js提供了内置的调试功能:
# 启动调试模式
node --inspect index.js
# 在代码执行前启用调试器
node --inspect-brk index.js
然后可以在Chrome浏览器中访问chrome://inspect,连接到Node.js调试实例。
3.4.2 VS Code调试配置
为VS Code创建launch.json配置文件:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/index.js",
"env": {
"NODE_ENV": "development"
}
},
{
"type": "node",
"request": "attach",
"name": "Attach to Process",
"port": 9229
}
]
}
4. 包管理工具
4.1 npm基础操作
npm是Node.js默认的包管理工具,提供了丰富的功能:
# 安装依赖
npm install express
# 安装特定版本
npm install express@4.17.1
# 安装开发依赖
npm install --save-dev jest
# 全局安装
npm install -g nodemon
# 卸载包
npm uninstall express
# 更新包
npm update express
# 列出过时的包
npm outdated
4.2 npm脚本配置
package.json中的scripts字段可以定义自定义命令:
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest",
"lint": "eslint .",
"build": "webpack --mode production",
"serve": "node dist/server.js",
"debug": "node --inspect index.js"
}
运行脚本:
# 运行脚本
npm run dev
# 运行预定义脚本可以省略run
npm start
npm test
4.3 yarn
Yarn是Facebook开发的替代npm的包管理工具,具有更快的安装速度和更好的依赖锁定。
4.3.1 安装yarn
# 使用npm安装yarn
npm install -g yarn
# macOS通过Homebrew安装
brew install yarn
4.3.2 yarn基础命令
# 初始化项目
yarn init
# 安装依赖
yarn add express
# 安装开发依赖
yarn add --dev jest
# 全局安装
yarn global add nodemon
# 卸载包
yarn remove express
# 更新包
yarn upgrade express
# 运行脚本
yarn start
4.4 pnpm
pnpm是一个快速、节省磁盘空间的包管理器,通过共享依赖降低磁盘占用。
4.4.1 安装pnpm
# 使用npm安装pnpm
npm install -g pnpm
# 使用curl安装
curl -fsSL https://get.pnpm.io/install.sh | sh -
4.4.2 pnpm基础命令
# 初始化项目
pnpm init
# 安装依赖
pnpm add express
# 安装开发依赖
pnpm add -D jest
# 全局安装
pnpm add -g nodemon
# 卸载包
pnpm remove express
# 更新包
pnpm update express
# 运行脚本
pnpm start
4.4.3 包管理器性能比较
graph TD
A[包管理器性能比较] --> B[安装速度]
A --> C[磁盘空间]
A --> D[锁文件准确性]
A --> E[依赖解析]
B --> B1[pnpm > yarn > npm]
C --> C1[pnpm > yarn ≈ npm]
D --> D1[pnpm ≈ yarn > npm]
E --> E1[pnpm ≈ yarn > npm]
style A fill:#66CDAA
style B fill:#87CEFA
style C fill:#87CEFA
style D fill:#87CEFA
style E fill:#87CEFA
5. Node.js项目结构最佳实践
5.1 标准项目结构
一个组织良好的Node.js项目通常有以下结构:
my-node-project/
├── node_modules/ # 依赖包目录
├── src/ # 源代码目录
│ ├── config/ # 配置文件
│ ├── controllers/ # 控制器
│ ├── middlewares/ # 中间件
│ ├── models/ # 数据模型
│ ├── routes/ # 路由定义
│ ├── services/ # 业务逻辑
│ ├── utils/ # 工具函数
│ └── index.js # 应用入口
├── tests/ # 测试文件
│ ├── unit/ # 单元测试
│ └── integration/ # 集成测试
├── public/ # 静态资源
├── views/ # 视图模板
├── scripts/ # 实用脚本
├── .env # 环境变量
├── .gitignore # Git忽略文件
├── .eslintrc.js # ESLint配置
├── .prettierrc # Prettier配置
├── jest.config.js # Jest配置
├── nodemon.json # Nodemon配置
├── package.json # 项目配置
├── package-lock.json # 依赖锁定
└── README.md # 项目文档
5.2 模块化开发实践
遵循模块化开发原则,将功能拆分为独立模块:
5.2.1 控制器示例
// src/controllers/userController.js
const User = require('../models/User');
const { createToken } = require('../utils/auth');
exports.register = async (req, res) => {
try {
const { name, email, password } = req.body;
// 检查用户是否已存在
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({ message: '该邮箱已被注册' });
}
// 创建新用户
const user = new User({ name, email, password });
await user.save();
// 生成token
const token = createToken(user._id);
res.status(201).json({ user: { id: user._id, name, email }, token });
} catch (error) {
res.status(500).json({ message: '服务器错误', error: error.message });
}
};
exports.login = async (req, res) => {
// 登录逻辑
};
exports.getProfile = async (req, res) => {
// 获取用户资料逻辑
};
5.2.2 路由示例
// src/routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
const { authenticate } = require('../middlewares/auth');
// 公开路由
router.post('/register', userController.register);
router.post('/login', userController.login);
// 受保护路由
router.get('/profile', authenticate, userController.getProfile);
router.put('/profile', authenticate, userController.updateProfile);
module.exports = router;
5.2.3 应用入口示例
// src/index.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const morgan = require('morgan');
require('dotenv').config();
// 导入路由
const userRoutes = require('./routes/userRoutes');
const productRoutes = require('./routes/productRoutes');
// 初始化应用
const app = express();
const PORT = process.env.PORT || 3000;
// 中间件
app.use(cors());
app.use(express.json());
app.use(morgan('dev'));
// 路由
app.use('/api/users', userRoutes);
app.use('/api/products', productRoutes);
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('服务器错误!');
});
// 连接数据库
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log('数据库连接成功');
// 启动服务器
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
})
.catch((err) => {
console.error('数据库连接失败:', err);
});
5.3 配置文件管理
集中管理配置参数可以提高维护性:
// src/config/index.js
require('dotenv').config();
module.exports = {
app: {
port: process.env.PORT || 3000,
env: process.env.NODE_ENV || 'development',
jwtSecret: process.env.JWT_SECRET || 'your-secret-key',
jwtExpiration: process.env.JWT_EXPIRATION || '1d',
},
database: {
uri: process.env.MONGODB_URI || 'mongodb://localhost:27017/myapp',
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
},
},
email: {
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT,
user: process.env.EMAIL_USER,
password: process.env.EMAIL_PASSWORD,
from: process.env.EMAIL_FROM,
},
// 其他配置...
};
6. Node.js应用部署
6.1 基本部署流程
Node.js应用的部署流程通常包括以下步骤:
6.2 使用进程管理工具
6.2.1 PM2
PM2是一个流行的Node.js进程管理工具,提供负载均衡、重启和监控功能。
# 全局安装PM2
npm install -g pm2
# 启动应用
pm2 start index.js
# 启动应用并命名
pm2 start index.js --name "my-api"
# 集群模式启动(利用多核CPU)
pm2 start index.js -i max
# 启动时配置环境变量
pm2 start index.js --env production
# 查看运行中的应用
pm2 list
# 监控应用
pm2 monit
# 查看应用日志
pm2 logs
# 重启应用
pm2 restart my-api
# 停止应用
pm2 stop my-api
# 删除应用
pm2 delete my-api
6.2.2 PM2配置文件
创建ecosystem.config.js文件实现更复杂的配置:
// ecosystem.config.js
module.exports = {
apps: [{
name: "my-api",
script: "src/index.js",
instances: "max",
exec_mode: "cluster",
autorestart: true,
watch: false,
max_memory_restart: "1G",
env: {
NODE_ENV: "development"
},
env_production: {
NODE_ENV: "production",
PORT: 8080
}
}]
};
使用配置文件启动:
pm2 start ecosystem.config.js
# 使用生产环境配置
pm2 start ecosystem.config.js --env production
6.3 Docker容器化部署
6.3.1 创建Dockerfile
# 使用官方Node.js镜像作为基础镜像
FROM node:16-alpine
# 设置工作目录
WORKDIR /usr/src/app
# 复制package.json和package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制应用程序代码
COPY . .
# 暴露端口
EXPOSE 3000
# 设置环境变量
ENV NODE_ENV=production
# 运行应用
CMD ["node", "src/index.js"]
6.3.2 创建.dockerignore文件
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.github
.gitignore
README.md
.env
.env.*
dist
coverage
6.3.3 构建和运行Docker容器
# 构建Docker镜像
docker build -t my-node-app .
# 运行容器
docker run -p 3000:3000 -d --name my-api my-node-app
# 查看日志
docker logs my-api
# 停止容器
docker stop my-api
6.3.4 Docker Compose配置
创建docker-compose.yml文件实现多容器部署:
version: '3'
services:
api:
build: .
ports:
- "3000:3000"
depends_on:
- mongo
environment:
- NODE_ENV=production
- MONGODB_URI=mongodb://mongo:27017/myapp
restart: always
mongo:
image: mongo:latest
volumes:
- mongodb_data:/data/db
ports:
- "27017:27017"
volumes:
mongodb_data:
启动服务:
docker-compose up -d
6.4 云平台部署
6.4.1 Heroku部署
Heroku是一个流行的PaaS平台,提供简易的Node.js应用部署:
# 安装Heroku CLI
npm install -g heroku
# 登录Heroku
heroku login
# 创建Heroku应用
heroku create my-node-app
# 配置环境变量
heroku config:set NODE_ENV=production
# 部署代码
git push heroku main
# 查看日志
heroku logs --tail
6.4.2 AWS Elastic Beanstalk部署
AWS Elastic Beanstalk是AWS提供的PaaS服务,支持Node.js应用部署:
# 安装AWS EB CLI
pip install awsebcli
# 初始化EB项目
eb init
# 创建环境
eb create my-node-env
# 部署代码
eb deploy
# 查看状态
eb status
7. Node.js性能优化
7.1 代码优化
7.1.1 异步编程最佳实践
// 使用async/await处理异步操作
async function getUserData(userId) {
try {
// 并行请求多个资源
const [user, orders, payments] = await Promise.all([
User.findById(userId),
Order.find({ userId }),
Payment.find({ userId })
]);
return { user, orders, payments };
} catch (error) {
console.error('获取用户数据失败:', error);
throw error;
}
}
// 避免嵌套回调(回调地狱)
// 不推荐
function processUser(userId, callback) {
getUser(userId, (err, user) => {
if (err) return callback(err);
getOrders(userId, (err, orders) => {
if (err) return callback(err);
processOrders(orders, (err, result) => {
if (err) return callback(err);
callback(null, result);
});
});
});
}
// 推荐使用Promise
function processUser(userId) {
return getUser(userId)
.then(user => getOrders(userId))
.then(orders => processOrders(orders))
.catch(error => {
console.error('处理用户数据失败:', error);
throw error;
});
}
7.1.2 内存管理
// 避免内存泄漏
const cache = new Map();
// 设置缓存上限
const MAX_CACHE_SIZE = 1000;
function addToCache(key, value) {
// 检查缓存大小
if (cache.size >= MAX_CACHE_SIZE) {
// 删除最早添加的项(简单实现)
const firstKey = cache.keys().next().value;
cache.delete(firstKey);
}
cache.set(key, value);
}
// 定期清理资源
const resources = new Map();
let cleanupInterval;
function startResourceCleanup() {
cleanupInterval = setInterval(() => {
const now = Date.now();
for (const [key, { value, expires }] of resources.entries()) {
if (now > expires) {
// 释放过期资源
resources.delete(key);
}
}
}, 60000); // 每分钟执行一次
}
function stopResourceCleanup() {
clearInterval(cleanupInterval);
}
7.2 数据库优化
// 索引优化
// 在Mongoose模型中添加索引
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, index: true },
username: { type: String, index: true },
lastLogin: { type: Date, index: true }
});
// 复合索引
userSchema.index({ createdAt: 1, status: 1 });
// 查询优化
// 只获取需要的字段
const users = await User.find({ status: 'active' }).select('name email');
// 使用投影
const orders = await Order.find({}, { items: 0 }); // 排除items字段
// 分页查询
const PAGE_SIZE = 20;
const page = req.query.page || 1;
const products = await Product
.find({ category: 'electronics' })
.skip((page - 1) * PAGE_SIZE)
.limit(PAGE_SIZE)
.lean(); // 返回纯JavaScript对象而非Mongoose文档
7.3 缓存策略
// 使用内存缓存
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600, checkperiod: 120 });
async function getProductById(productId) {
// 检查缓存
const cachedProduct = cache.get(`product:${productId}`);
if (cachedProduct) {
return cachedProduct;
}
// 从数据库获取
const product = await Product.findById(productId);
// 存入缓存
cache.set(`product:${productId}`, product, 3600); // 缓存1小时
return product;
}
// 使用Redis缓存
const Redis = require('ioredis');
const redis = new Redis({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT
});
async function getUserProfile(userId) {
// 从Redis获取缓存
const cachedProfile = await redis.get(`user:${userId}:profile`);
if (cachedProfile) {
return JSON.parse(cachedProfile);
}
// 从数据库获取
const profile = await User.findById(userId).select('-password');
// 存入Redis
await redis.set(
`user:${userId}:profile`,
JSON.stringify(profile),
'EX',
3600
); // 缓存1小时
return profile;
}
结语
感谢您的阅读!期待您的一键三连!欢迎指正!