Skip to content

快速开始

概述

在本章中,您将创建第一个 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

演示的最佳实践

  1. 错误处理:始终处理异步操作中的错误
  2. 模块组织:将功能分离到模块中
  3. Async/Await:使用现代异步模式编写更清晰的代码
  4. 文件操作:使用基于 Promise 的文件操作
  5. 命令行界面:正确处理命令行参数

要避免的常见陷阱

  1. 阻塞操作:在生产环境中不要使用同步操作
  2. 未处理的错误:始终处理 Promise 拒绝
  3. 全局变量:避免污染全局命名空间
  4. 硬编码值:使用环境变量进行配置

下一步

在下一章中,我们将深入探讨 Node.js 基础知识,探索使 Node.js 强大的核心概念。

实践练习

  1. 创建一个简单的计算器 CLI 应用程序
  2. 构建一个按扩展名排序文件的文件组织器
  3. 创建一个提供静态文件的基本 HTTP 服务器
  4. 使用文件操作实现一个简单的日志系统

关键要点

  • Node.js 应用程序从一个简单的 JavaScript 文件开始
  • 内置模块提供强大的功能
  • 异步编程在 Node.js 中至关重要
  • 模块有助于将代码组织成可重用的组件
  • 错误处理对于健壮的应用程序至关重要
  • 命令行参数支持交互式应用程序

本站内容仅供学习和研究使用。