快速开始
概述
在本章中,您将创建第一个 Node.js 应用程序,并通过实际示例理解基本概念。我们将构建一个简单的 Web 服务器并探索 Node.js 的基本功能。
您的第一个 Node.js 应用程序
Hello World 控制台应用程序
创建一个名为 hello.js 的文件:
javascript
// hello.js
console.log('Hello, Node.js!');
console.log('Current directory:', __dirname);
console.log('Current file:', __filename);
console.log('Node.js version:', process.version);运行应用程序:
bash
node hello.js理解全局对象
Node.js 提供了几个全局对象:
javascript
// globals.js
console.log('=== Global Objects ===');
console.log('__dirname:', __dirname);
console.log('__filename:', __filename);
console.log('process.argv:', process.argv);
console.log('process.env.NODE_ENV:', process.env.NODE_ENV);
// Process information
console.log('\n=== Process Info ===');
console.log('Process ID:', process.pid);
console.log('Platform:', process.platform);
console.log('Architecture:', process.arch);
console.log('Memory usage:', process.memoryUsage());创建简单的 Web 服务器
基本 HTTP 服务器
javascript
// server.js
const http = require('http');
// 创建服务器
const server = http.createServer((req, res) => {
// 设置响应头
res.writeHead(200, { 'Content-Type': 'text/html' });
// 发送响应
res.end('<h1>Hello from Node.js Server!</h1>');
});
// 启动服务器
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});运行服务器:
bash
node server.js在浏览器中访问 http://localhost:3000。
带路由的增强服务器
javascript
// enhanced-server.js
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
// Set common headers
res.setHeader('Content-Type', 'text/html');
// Simple routing
if (path === '/' && method === 'GET') {
res.statusCode = 200;
res.end(`
<h1>Welcome to Node.js!</h1>
<p>Try these routes:</p>
<ul>
<li><a href="/about">About</a></li>
<li><a href="/api/users">API Users</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
`);
} else if (path === '/about' && method === 'GET') {
res.statusCode = 200;
res.end('<h1>About Page</h1><p>This is a Node.js application!</p>');
} else if (path === '/api/users' && method === 'GET') {
res.setHeader('Content-Type', 'application/json');
res.statusCode = 200;
res.end(JSON.stringify({
users: [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
]
}));
} else if (path === '/contact' && method === 'GET') {
res.statusCode = 200;
res.end('<h1>Contact</h1><p>Email: contact@example.com</p>');
} else {
res.statusCode = 404;
res.end('<h1>404 - Page Not Found</h1>');
}
});
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Enhanced server running at http://localhost:${PORT}`);
});使用模块
创建自定义模块
创建 math-utils.js:
javascript
// math-utils.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('Division by zero is not allowed');
}
return a / b;
}
// 导出函数
module.exports = {
add,
subtract,
multiply,
divide
};使用自定义模块:
javascript
// app.js
const mathUtils = require('./math-utils');
console.log('Addition:', mathUtils.add(5, 3));
console.log('Subtraction:', mathUtils.subtract(10, 4));
console.log('Multiplication:', mathUtils.multiply(6, 7));
console.log('Division:', mathUtils.divide(15, 3));
try {
console.log('Division by zero:', mathUtils.divide(10, 0));
} catch (error) {
console.error('Error:', error.message);
}使用内置模块
javascript
// built-in-modules.js
const fs = require('fs');
const path = require('path');
const os = require('os');
// File system operations
console.log('=== File System ===');
console.log('Current directory contents:');
fs.readdirSync('.').forEach(file => {
console.log('-', file);
});
// Path operations
console.log('\n=== Path Operations ===');
console.log('Join paths:', path.join(__dirname, 'files', 'data.txt'));
console.log('File extension:', path.extname('app.js'));
console.log('Base name:', path.basename('/users/john/documents/file.txt'));
// Operating system info
console.log('\n=== OS Information ===');
console.log('Platform:', os.platform());
console.log('CPU architecture:', os.arch());
console.log('Total memory:', Math.round(os.totalmem() / 1024 / 1024), 'MB');
console.log('Free memory:', Math.round(os.freemem() / 1024 / 1024), 'MB');
console.log('Uptime:', Math.round(os.uptime() / 3600), 'hours');异步编程基础
回调
javascript
// callbacks.js
const fs = require('fs');
// 同步(阻塞)
console.log('=== Synchronous File Reading ===');
try {
const data = fs.readFileSync('package.json', 'utf8');
console.log('File read successfully (sync)');
} catch (error) {
console.error('Error reading file (sync):', error.message);
}
// 异步(非阻塞)
console.log('\n=== Asynchronous File Reading ===');
fs.readFile('package.json', 'utf8', (error, data) => {
if (error) {
console.error('Error reading file (async):', error.message);
return;
}
console.log('File read successfully (async)');
console.log('File size:', data.length, 'characters');
});
console.log('This line executes immediately (async)');Promise
javascript
// promises.js
const fs = require('fs').promises;
// 使用 Promise
console.log('=== Promise-based File Reading ===');
fs.readFile('package.json', 'utf8')
.then(data => {
console.log('File read successfully (promise)');
return JSON.parse(data);
})
.then(packageInfo => {
console.log('Package name:', packageInfo.name);
console.log('Package version:', packageInfo.version);
})
.catch(error => {
console.error('Error:', error.message);
});
console.log('This line executes immediately (promise)');Async/Await
javascript
// async-await.js
const fs = require('fs').promises;
async function readPackageInfo() {
try {
console.log('=== Async/Await File Reading ===');
const data = await fs.readFile('package.json', 'utf8');
console.log('File read successfully (async/await)');
const packageInfo = JSON.parse(data);
console.log('Package name:', packageInfo.name);
console.log('Package version:', packageInfo.version);
return packageInfo;
} catch (error) {
console.error('Error:', error.message);
throw error;
}
}
// Call async function
readPackageInfo()
.then(info => {
console.log('Processing complete');
})
.catch(error => {
console.error('Failed to read package info');
});
console.log('This line executes immediately (async/await)');构建完整示例
让我们创建一个基于文件的简单笔记应用程序:
javascript
// notes-app.js
const fs = require('fs').promises;
const path = require('path');
class NotesApp {
constructor() {
this.notesFile = path.join(__dirname, 'notes.json');
}
async loadNotes() {
try {
const data = await fs.readFile(this.notesFile, 'utf8');
return JSON.parse(data);
} catch (error) {
// File doesn't exist, return empty array
return [];
}
}
async saveNotes(notes) {
await fs.writeFile(this.notesFile, JSON.stringify(notes, null, 2));
}
async addNote(title, content) {
const notes = await this.loadNotes();
const newNote = {
id: Date.now(),
title,
content,
createdAt: new Date().toISOString()
};
notes.push(newNote);
await this.saveNotes(notes);
return newNote;
}
async listNotes() {
const notes = await this.loadNotes();
return notes;
}
async deleteNote(id) {
const notes = await this.loadNotes();
const filteredNotes = notes.filter(note => note.id !== id);
await this.saveNotes(filteredNotes);
return filteredNotes.length < notes.length;
}
}
// Usage example
async function main() {
const app = new NotesApp();
try {
// Add some notes
await app.addNote('First Note', 'This is my first note in Node.js!');
await app.addNote('Learning Node.js', 'Node.js is awesome for server-side development.');
// List all notes
const notes = await app.listNotes();
console.log('All Notes:');
notes.forEach(note => {
console.log(`- ${note.title} (ID: ${note.id})`);
console.log(` ${note.content}`);
console.log(` Created: ${note.createdAt}\n`);
});
console.log(`Total notes: ${notes.length}`);
} catch (error) {
console.error('Error:', error.message);
}
}
// Run the application
main();命令行参数
javascript
// cli-app.js
const args = process.argv.slice(2);
if (args.length === 0) {
console.log('Usage: node cli-app.js <command> [arguments]');
console.log('Commands:');
console.log(' greet <name> - Greet someone');
console.log(' calc <a> <b> - Add two numbers');
console.log(' info - Show system info');
process.exit(1);
}
const command = args[0];
switch (command) {
case 'greet':
const name = args[1] || 'World';
console.log(`Hello, ${name}!`);
break;
case 'calc':
const a = parseFloat(args[1]);
const b = parseFloat(args[2]);
if (isNaN(a) || isNaN(b)) {
console.error('Please provide two valid numbers');
process.exit(1);
}
console.log(`${a} + ${b} = ${a + b}`);
break;
case 'info':
console.log('System Information:');
console.log('- Node.js version:', process.version);
console.log('- Platform:', process.platform);
console.log('- Architecture:', process.arch);
console.log('- Current directory:', process.cwd());
break;
default:
console.error(`Unknown command: ${command}`);
process.exit(1);
}测试 CLI 应用程序:
bash
node cli-app.js greet John
node cli-app.js calc 15 25
node cli-app.js info演示的最佳实践
- 错误处理:始终处理异步操作中的错误
- 模块组织:将功能分离到模块中
- Async/Await:使用现代异步模式编写更清晰的代码
- 文件操作:使用基于 Promise 的文件操作
- 命令行界面:正确处理命令行参数
要避免的常见陷阱
- 阻塞操作:在生产环境中不要使用同步操作
- 未处理的错误:始终处理 Promise 拒绝
- 全局变量:避免污染全局命名空间
- 硬编码值:使用环境变量进行配置
下一步
在下一章中,我们将深入探讨 Node.js 基础知识,探索使 Node.js 强大的核心概念。
实践练习
- 创建一个简单的计算器 CLI 应用程序
- 构建一个按扩展名排序文件的文件组织器
- 创建一个提供静态文件的基本 HTTP 服务器
- 使用文件操作实现一个简单的日志系统
关键要点
- Node.js 应用程序从一个简单的 JavaScript 文件开始
- 内置模块提供强大的功能
- 异步编程在 Node.js 中至关重要
- 模块有助于将代码组织成可重用的组件
- 错误处理对于健壮的应用程序至关重要
- 命令行参数支持交互式应用程序