Node.js 全局对象与全局变量

章节介绍

Node.js 提供了许多全局对象和全局变量,这些对象和变量可以在任何模块中直接使用,无需显式导入。理解这些全局对象对于编写高效的 Node.js 应用程序至关重要。本教程将详细介绍 Node.js 的全局对象和全局变量,帮助您掌握 Node.js 的运行环境。

核心知识点

全局对象概述

Node.js 的全局对象类似于浏览器中的 window 对象,但有一些重要的区别:

  1. global 对象:Node.js 的全局命名空间
  2. process 对象:提供当前 Node.js 进程的信息和控制
  3. console 对象:用于打印输出和调试
  4. 定时器函数:setTimeout、setInterval、setImmediate 等
  5. Buffer 类:用于处理二进制数据
全局对象结构:

┌─────────────────────────────────────┐
│           global 对象                │
├─────────────────────────────────────┤
│  ┌─────────────┐  ┌──────────────┐  │
│  │  process    │  │   console    │  │
│  └─────────────┘  └──────────────┘  │
│  ┌─────────────┐  ┌──────────────┐  │
│  │  setTimeout │  │  setInterval  │  │
│  └─────────────┘  └──────────────┘  │
│  ┌─────────────┐  ┌──────────────┐  │
│  │   Buffer    │  │   __dirname  │  │
│  └─────────────┘  └──────────────┘  │
│  ┌─────────────┐  ┌──────────────┐  │
│  │  __filename │  │   require()   │  │
│  └─────────────┘  └──────────────┘  │
└─────────────────────────────────────┘

global 对象

global 对象是 Node.js 的全局命名空间,所有全局变量和函数都是 global 对象的属性。

// 访问 global 对象
console.log(global);

// 在全局作用域中声明的变量会成为 global 的属性
global.myGlobal = '全局变量';
console.log(global.myGlobal);  // 全局变量

// 等同于直接声明(不推荐)
myGlobal2 = '另一个全局变量';
console.log(global.myGlobal2);  // 另一个全局变量

// 检查全局变量是否存在
if (global.myGlobal) {
  console.log('myGlobal 存在');
}

// 遍历 global 对象的所有属性
for (const key in global) {
  console.log(key);
}

process 对象

process 对象提供当前 Node.js 进程的信息和控制,是一个非常重要的全局对象。

进程信息

// 获取进程 ID
console.log('进程 ID:', process.pid);

// 获取 Node.js 版本
console.log('Node.js 版本:', process.version);
console.log('V8 版本:', process.versions.v8);

// 获取平台信息
console.log('操作系统:', process.platform);  // win32, darwin, linux
console.log('CPU 架构:', process.arch);        // x64, arm, ia32

// 获取执行参数
console.log('执行路径:', process.execPath);
console.log('当前工作目录:', process.cwd());
console.log('脚本路径:', process.argv[0]);
console.log('命令行参数:', process.argv.slice(2));

// 获取环境变量
console.log('环境变量:', process.env);
console.log('PATH:', process.env.PATH);
console.log('HOME:', process.env.HOME);

进程控制

// 退出进程
process.exit(0);  // 正常退出
process.exit(1);  // 异常退出

// 设置退出代码
process.exitCode = 1;

// 监听退出事件
process.on('exit', (code) => {
  console.log(`进程退出,退出代码:${code}`);
});

// 发送信号
process.kill(process.pid, 'SIGTERM');

// 设置进程标题
process.title = 'My Node.js App';
console.log('进程标题:', process.title);

// 改变工作目录
process.chdir('/path/to/directory');
console.log('新的工作目录:', process.cwd());

// 设置用户 ID 和组 ID(需要 root 权限)
// process.setuid(1000);
// process.setgid(1000);

内存和 CPU 信息

// 内存使用情况
const memoryUsage = process.memoryUsage();
console.log('内存使用情况:');
console.log('  RSS(常驻内存):', (memoryUsage.rss / 1024 / 1024).toFixed(2), 'MB');
console.log('  堆总大小:', (memoryUsage.heapTotal / 1024 / 1024).toFixed(2), 'MB');
console.log('  堆已使用:', (memoryUsage.heapUsed / 1024 / 1024).toFixed(2), 'MB');
console.log('  外部内存:', (memoryUsage.external / 1024 / 1024).toFixed(2), 'MB');

// CPU 使用情况
const cpuUsage = process.cpuUsage();
console.log('CPU 使用情况:');
console.log('  用户态 CPU 时间:', cpuUsage.user / 1000, 'ms');
console.log('  内核态 CPU 时间:', cpuUsage.system / 1000, 'ms');

// 获取 CPU 信息
console.log('CPU 信息:', process.cpuUsage());

标准输入输出

// 标准输入
process.stdin.setEncoding('utf8');
process.stdin.on('data', (data) => {
  console.log('输入:', data.trim());
});

// 标准输出
process.stdout.write('标准输出:Hello World\n');

// 标准错误
process.stderr.write('标准错误:Error message\n');

// 重定向输出
const fs = require('fs');
const output = fs.createWriteStream('output.log');
process.stdout.write = output.write.bind(output);
console.log('这条消息会被写入文件');

进程事件

// 监听未捕获的异常
process.on('uncaughtException', (error) => {
  console.error('未捕获的异常:', error);
  process.exit(1);
});

// 监听未处理的 Promise 拒绝
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的 Promise 拒绝:', reason);
});

// 监听警告
process.on('warning', (warning) => {
  console.warn('警告:', warning.name, warning.message);
});

// 监听信号
process.on('SIGINT', () => {
  console.log('收到 SIGINT 信号,准备退出...');
  process.exit(0);
});

// 监听消息(用于进程间通信)
process.on('message', (message) => {
  console.log('收到消息:', message);
});

// 发送消息
if (process.send) {
  process.send({ type: 'greeting', data: 'Hello' });
}

console 对象

console 对象用于向标准输出和标准错误流打印信息。

基本输出方法

// 打印到标准输出
console.log('普通日志');
console.log('格式化日志:%s, %d, %j', '字符串', 100, { key: 'value' });

// 打印到标准错误
console.error('错误信息');
console.error('错误详情:', new Error('Something went wrong'));

// 打印警告
console.warn('警告信息');

// 打印信息
console.info('信息日志');

// 打印调试信息
console.debug('调试信息');

格式化输出

// 格式化占位符
console.log('字符串:%s', 'Hello');
console.log('数字:%d', 42);
console.log('浮点数:%.2f', 3.14159);
console.log('JSON:%j', { name: '张三', age: 25 });
console.log('对象:%o', { name: '张三', age: 25 });

// 颜色输出
console.log('\x1b[31m红色文本\x1b[0m');
console.log('\x1b[32m绿色文本\x1b[0m');
console.log('\x1b[33m黄色文本\x1b[0m');
console.log('\x1b[34m蓝色文本\x1b[0m');

// 使用 ANSI 颜色代码
const colors = {
  reset: '\x1b[0m',
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m'
};

console.log(`${colors.red}错误信息${colors.reset}`);
console.log(`${colors.green}成功信息${colors.reset}`);

高级输出方法

// 打印表格
console.table([
  { name: '张三', age: 25, city: '北京' },
  { name: '李四', age: 30, city: '上海' },
  { name: '王五', age: 28, city: '广州' }
]);

// 打印堆栈跟踪
console.trace('堆栈跟踪:');

// 计时
console.time('timer');
setTimeout(() => {
  console.timeEnd('timer');  // timer: 1000.123ms
}, 1000);

// 计时标签
console.time('loop');
for (let i = 0; i < 1000000; i++) {
  // 循环
}
console.timeEnd('loop');

// 断言
console.assert(1 === 1, '1 等于 1');
console.assert(1 === 2, '1 不等于 2');  // AssertionError: 1 不等于 2

// 分组输出
console.group('分组 1');
console.log('消息 1');
console.log('消息 2');
console.groupEnd();

console.groupCollapsed('折叠分组');
console.log('消息 3');
console.log('消息 4');
console.groupEnd();

定时器函数

Node.js 提供了多种定时器函数,用于延迟执行或重复执行代码。

setTimeout

// 基本使用
setTimeout(() => {
  console.log('1 秒后执行');
}, 1000);

// 带参数
function greet(name) {
  console.log(`你好,${name}!`);
}

setTimeout(greet, 1000, '张三');

// 清除定时器
const timerId = setTimeout(() => {
  console.log('这条消息不会被打印');
}, 1000);

clearTimeout(timerId);

// 嵌套定时器
setTimeout(() => {
  console.log('第一步');
  setTimeout(() => {
    console.log('第二步');
    setTimeout(() => {
      console.log('第三步');
    }, 1000);
  }, 1000);
}, 1000);

setInterval

// 基本使用
let count = 0;
const intervalId = setInterval(() => {
  count++;
  console.log(`计数:${count}`);
  
  if (count >= 5) {
    clearInterval(intervalId);
  }
}, 1000);

// 带参数
function logMessage(message) {
  console.log(message);
}

setInterval(logMessage, 1000, '定时消息');

// 清除定时器
const timerId = setInterval(() => {
  console.log('每秒执行一次');
}, 1000);

setTimeout(() => {
  clearInterval(timerId);
}, 5000);

setImmediate

// 在 I/O 事件回调之后立即执行
setImmediate(() => {
  console.log('setImmediate 执行');
});

// 与 setTimeout 的区别
console.log('开始');

setTimeout(() => {
  console.log('setTimeout');
}, 0);

setImmediate(() => {
  console.log('setImmediate');
});

console.log('结束');

// 执行顺序可能是:
// 开始
// 结束
// setTimeout
// setImmediate

// 或者在 I/O 回调中
const fs = require('fs');
fs.readFile(__filename, () => {
  setImmediate(() => {
    console.log('setImmediate 在 I/O 回调中');
  });
  
  setTimeout(() => {
    console.log('setTimeout 在 I/O 回调中');
  }, 0);
});

process.nextTick

// 在当前操作完成后立即执行
console.log('开始');

process.nextTick(() => {
  console.log('process.nextTick');
});

console.log('结束');

// 执行顺序:
// 开始
// 结束
// process.nextTick

// 与 setImmediate 的区别
console.log('开始');

process.nextTick(() => {
  console.log('nextTick 1');
  process.nextTick(() => {
    console.log('nextTick 2');
  });
});

setImmediate(() => {
  console.log('setImmediate 1');
  setImmediate(() => {
    console.log('setImmediate 2');
  });
});

// 执行顺序:
// 开始
// nextTick 1
// nextTick 2
// setImmediate 1
// setImmediate 2

其他全局变量

// __dirname:当前模块的目录名
console.log('__dirname:', __dirname);

// __filename:当前模块的文件名
console.log('__filename:', __filename);

// require:引入模块的函数
const fs = require('fs');

// module:当前模块的引用
console.log('当前模块:', module.id);

// exports:当前模块的导出对象
exports.myFunction = function() {
  console.log('我的函数');
};

// Buffer:Buffer 类
const buffer = Buffer.from('Hello World');
console.log(buffer.toString());

// URL 和 URLSearchParams(全局可用)
const url = new URL('https://example.com/path?query=value');
console.log(url.hostname);
console.log(url.searchParams.get('query'));

实用案例分析

案例 1:命令行工具

创建一个命令行工具,解析命令行参数并执行相应操作。

// cli.js
const fs = require('fs');
const path = require('path');

function printHelp() {
  console.log(`
使用方法:
  node cli.js [命令] [参数]

命令:
  help              显示帮助信息
  create <name>     创建新文件
  read <name>       读取文件内容
  delete <name>     删除文件
  list              列出当前目录的文件
  version           显示版本信息

示例:
  node cli.js create test.txt
  node cli.js read test.txt
  node cli.js delete test.txt
  node cli.js list
  `);
}

function createFile(name) {
  const filePath = path.join(process.cwd(), name);
  
  try {
    fs.writeFileSync(filePath, 'Hello World');
    console.log(`文件 ${name} 创建成功`);
  } catch (error) {
    console.error(`创建文件失败:${error.message}`);
    process.exit(1);
  }
}

function readFile(name) {
  const filePath = path.join(process.cwd(), name);
  
  try {
    const content = fs.readFileSync(filePath, 'utf8');
    console.log(`文件 ${name} 的内容:`);
    console.log(content);
  } catch (error) {
    console.error(`读取文件失败:${error.message}`);
    process.exit(1);
  }
}

function deleteFile(name) {
  const filePath = path.join(process.cwd(), name);
  
  try {
    fs.unlinkSync(filePath);
    console.log(`文件 ${name} 删除成功`);
  } catch (error) {
    console.error(`删除文件失败:${error.message}`);
    process.exit(1);
  }
}

function listFiles() {
  const dir = process.cwd();
  
  try {
    const files = fs.readdirSync(dir);
    console.log('当前目录的文件:');
    files.forEach(file => {
      const filePath = path.join(dir, file);
      const stats = fs.statSync(filePath);
      const type = stats.isDirectory() ? '目录' : '文件';
      console.log(`  ${file} (${type})`);
    });
  } catch (error) {
    console.error(`列出文件失败:${error.message}`);
    process.exit(1);
  }
}

function showVersion() {
  console.log('CLI 工具版本:1.0.0');
  console.log(`Node.js 版本:${process.version}`);
}

function main() {
  const args = process.argv.slice(2);
  
  if (args.length === 0) {
    printHelp();
    return;
  }
  
  const command = args[0];
  const params = args.slice(1);
  
  switch (command) {
    case 'help':
      printHelp();
      break;
    case 'create':
      if (params.length === 0) {
        console.error('错误:请指定文件名');
        process.exit(1);
      }
      createFile(params[0]);
      break;
    case 'read':
      if (params.length === 0) {
        console.error('错误:请指定文件名');
        process.exit(1);
      }
      readFile(params[0]);
      break;
    case 'delete':
      if (params.length === 0) {
        console.error('错误:请指定文件名');
        process.exit(1);
      }
      deleteFile(params[0]);
      break;
    case 'list':
      listFiles();
      break;
    case 'version':
      showVersion();
      break;
    default:
      console.error(`未知命令:${command}`);
      printHelp();
      process.exit(1);
  }
}

main();

案例 2:定时任务管理器

创建一个定时任务管理器,可以添加、删除和执行定时任务。

// task-scheduler.js
class TaskScheduler {
  constructor() {
    this.tasks = new Map();
    this.taskId = 0;
  }
  
  addTask(fn, delay, ...args) {
    const id = ++this.taskId;
    const timerId = setTimeout(() => {
      try {
        fn(...args);
        this.tasks.delete(id);
        console.log(`任务 ${id} 执行完成`);
      } catch (error) {
        console.error(`任务 ${id} 执行失败:`, error);
        this.tasks.delete(id);
      }
    }, delay);
    
    this.tasks.set(id, {
      id,
      fn,
      delay,
      args,
      timerId,
      createdAt: new Date()
    });
    
    console.log(`任务 ${id} 已添加,将在 ${delay}ms 后执行`);
    return id;
  }
  
  addRecurringTask(fn, interval, ...args) {
    const id = ++this.taskId;
    const timerId = setInterval(() => {
      try {
        fn(...args);
        console.log(`周期性任务 ${id} 执行完成`);
      } catch (error) {
        console.error(`周期性任务 ${id} 执行失败:`, error);
      }
    }, interval);
    
    this.tasks.set(id, {
      id,
      fn,
      interval,
      args,
      timerId,
      createdAt: new Date(),
      recurring: true
    });
    
    console.log(`周期性任务 ${id} 已添加,每 ${interval}ms 执行一次`);
    return id;
  }
  
  removeTask(id) {
    const task = this.tasks.get(id);
    if (task) {
      if (task.recurring) {
        clearInterval(task.timerId);
      } else {
        clearTimeout(task.timerId);
      }
      this.tasks.delete(id);
      console.log(`任务 ${id} 已移除`);
      return true;
    }
    return false;
  }
  
  listTasks() {
    console.log('当前任务列表:');
    if (this.tasks.size === 0) {
      console.log('  没有任务');
      return;
    }
    
    this.tasks.forEach((task, id) => {
      const type = task.recurring ? '周期性' : '一次性';
      const time = task.delay || task.interval;
      console.log(`  任务 ${id}:${type},${time}ms`);
    });
  }
  
  clearAll() {
    this.tasks.forEach((task, id) => {
      if (task.recurring) {
        clearInterval(task.timerId);
      } else {
        clearTimeout(task.timerId);
      }
    });
    this.tasks.clear();
    console.log('所有任务已清除');
  }
}

// 使用示例
const scheduler = new TaskScheduler();

// 添加一次性任务
scheduler.addTask(() => {
  console.log('任务 1:发送邮件');
}, 2000);

scheduler.addTask((name) => {
  console.log(`任务 2:欢迎 ${name}`);
}, 3000, '张三');

// 添加周期性任务
scheduler.addRecurringTask(() => {
  console.log('周期性任务:检查系统状态');
}, 5000);

scheduler.addRecurringTask(() => {
  console.log('周期性任务:备份数据');
}, 10000);

// 列出任务
scheduler.listTasks();

// 移除任务
setTimeout(() => {
  const taskId = 2;
  scheduler.removeTask(taskId);
  console.log(`\n移除任务 ${taskId} 后:`);
  scheduler.listTasks();
}, 4000);

// 清除所有任务
setTimeout(() => {
  console.log('\n清除所有任务:');
  scheduler.clearAll();
}, 15000);

案例 3:进度条显示

创建一个进度条显示工具,用于显示长时间运行任务的进度。

// progress-bar.js
class ProgressBar {
  constructor(total, options = {}) {
    this.total = total;
    this.current = 0;
    this.width = options.width || 40;
    this.completeChar = options.completeChar || '=';
    this.incompleteChar = options.incompleteChar || '-';
    this.showPercent = options.showPercent !== false;
    this.showTime = options.showTime !== false;
    this.startTime = Date.now();
  }
  
  update(current) {
    this.current = current;
    this.render();
  }
  
  increment() {
    this.current++;
    this.render();
  }
  
  render() {
    const percent = this.current / this.total;
    const completed = Math.floor(this.width * percent);
    const incomplete = this.width - completed;
    
    const bar = this.completeChar.repeat(completed) + 
                this.incompleteChar.repeat(incomplete);
    
    let output = `\r[${bar}]`;
    
    if (this.showPercent) {
      output += ` ${(percent * 100).toFixed(1)}%`;
    }
    
    if (this.showTime) {
      const elapsed = Date.now() - this.startTime;
      const remaining = this.current > 0 
        ? (elapsed / this.current) * (this.total - this.current)
        : 0;
      
      output += ` | 已用:${this.formatTime(elapsed)} | 剩余:${this.formatTime(remaining)}`;
    }
    
    process.stdout.write(output);
    
    if (this.current >= this.total) {
      process.stdout.write('\n');
    }
  }
  
  formatTime(ms) {
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);
    
    if (hours > 0) {
      return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
    } else if (minutes > 0) {
      return `${minutes}m ${seconds % 60}s`;
    } else {
      return `${seconds}s`;
    }
  }
}

// 使用示例
const total = 100;
const progressBar = new ProgressBar(total, {
  width: 50,
  showPercent: true,
  showTime: true
});

console.log('开始处理...');

let current = 0;
const interval = setInterval(() => {
  current += Math.floor(Math.random() * 5) + 1;
  
  if (current >= total) {
    current = total;
    clearInterval(interval);
  }
  
  progressBar.update(current);
}, 100);

代码示例

示例 1:系统信息监控

// system-monitor.js
function printSystemInfo() {
  console.log('=== 系统信息 ===');
  
  // 进程信息
  console.log('\n进程信息:');
  console.log('  进程 ID:', process.pid);
  console.log('  Node.js 版本:', process.version);
  console.log('  平台:', process.platform);
  console.log('  架构:', process.arch);
  console.log('  工作目录:', process.cwd());
  
  // 内存信息
  const memory = process.memoryUsage();
  console.log('\n内存使用:');
  console.log('  RSS:', (memory.rss / 1024 / 1024).toFixed(2), 'MB');
  console.log('  堆总大小:', (memory.heapTotal / 1024 / 1024).toFixed(2), 'MB');
  console.log('  堆已使用:', (memory.heapUsed / 1024 / 1024).toFixed(2), 'MB');
  console.log('  外部内存:', (memory.external / 1024 / 1024).toFixed(2), 'MB');
  
  // CPU 信息
  const cpu = process.cpuUsage();
  console.log('\nCPU 使用:');
  console.log('  用户态:', (cpu.user / 1000000).toFixed(2), 's');
  console.log('  内核态:', (cpu.system / 1000000).toFixed(2), 's');
  
  // 环境变量
  console.log('\n环境变量(部分):');
  console.log('  PATH:', process.env.PATH);
  console.log('  HOME:', process.env.HOME);
  console.log('  USER:', process.env.USER);
  console.log('  LANG:', process.env.LANG);
}

printSystemInfo();

// 定时更新
setInterval(() => {
  console.log('\n=== 更新时间:', new Date().toLocaleTimeString(), '===');
  const memory = process.memoryUsage();
  console.log('堆使用:', (memory.heapUsed / 1024 / 1024).toFixed(2), 'MB');
}, 5000);

示例 2:日志记录器

// logger.js
const fs = require('fs');
const path = require('path');

class Logger {
  constructor(options = {}) {
    this.name = options.name || 'App';
    this.level = options.level || 'info';
    this.logFile = options.logFile || null;
    this.levels = {
      error: 0,
      warn: 1,
      info: 2,
      debug: 3
    };
  }
  
  formatMessage(level, message) {
    const timestamp = new Date().toISOString();
    return `[${timestamp}] [${this.name}] [${level.toUpperCase()}] ${message}`;
  }
  
  log(level, message) {
    if (this.levels[level] > this.levels[this.level]) {
      return;
    }
    
    const formattedMessage = this.formatMessage(level, message);
    
    switch (level) {
      case 'error':
        console.error(formattedMessage);
        break;
      case 'warn':
        console.warn(formattedMessage);
        break;
      case 'debug':
        console.debug(formattedMessage);
        break;
      default:
        console.log(formattedMessage);
    }
    
    if (this.logFile) {
      this.writeToFile(formattedMessage);
    }
  }
  
  writeToFile(message) {
    try {
      fs.appendFileSync(this.logFile, message + '\n', 'utf8');
    } catch (error) {
      console.error('写入日志文件失败:', error);
    }
  }
  
  error(message) {
    this.log('error', message);
  }
  
  warn(message) {
    this.log('warn', message);
  }
  
  info(message) {
    this.log('info', message);
  }
  
  debug(message) {
    this.log('debug', message);
  }
}

// 使用示例
const logger = new Logger({
  name: 'MyApp',
  level: 'debug',
  logFile: path.join(__dirname, 'app.log')
});

logger.info('应用启动');
logger.debug('调试信息');
logger.warn('警告信息');
logger.error('错误信息');

// 模拟错误
try {
  throw new Error('模拟错误');
} catch (error) {
  logger.error(`发生错误:${error.message}`);
  logger.debug(error.stack);
}

示例 3:命令行参数解析器

// args-parser.js
function parseArgs(args) {
  const parsed = {
    _: [],
    flags: {},
    options: {}
  };
  
  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    
    if (arg.startsWith('--')) {
      const key = arg.slice(2);
      const nextArg = args[i + 1];
      
      if (nextArg && !nextArg.startsWith('-')) {
        parsed.options[key] = nextArg;
        i++;
      } else {
        parsed.flags[key] = true;
      }
    } else if (arg.startsWith('-')) {
      const key = arg.slice(1);
      const nextArg = args[i + 1];
      
      if (nextArg && !nextArg.startsWith('-')) {
        parsed.options[key] = nextArg;
        i++;
      } else {
        parsed.flags[key] = true;
      }
    } else {
      parsed._.push(arg);
    }
  }
  
  return parsed;
}

// 使用示例
const args = process.argv.slice(2);
const parsed = parseArgs(args);

console.log('解析结果:');
console.log('位置参数:', parsed._);
console.log('标志:', parsed.flags);
console.log('选项:', parsed.options);

// 示例命令:
// node args-parser.js input.txt output.txt --verbose --output=out.txt -f json

实现技巧与注意事项

全局变量使用建议

  1. 避免污染全局命名空间:尽量减少全局变量的使用
  2. 使用模块代替全局变量:通过模块系统共享数据
  3. **谨慎使用 process.exit()**:确保资源正确释放后再退出
  4. 处理未捕获的异常:监听 uncaughtException 事件

console 输出优化

  1. 使用适当的日志级别:error、warn、info、debug
  2. 结构化日志:使用 JSON 格式便于解析
  3. 避免过度输出:减少不必要的日志
  4. 使用日志库:如 winston、bunyan 等

定时器使用注意事项

  1. 清除不需要的定时器:避免内存泄漏
  2. 注意定时器精度:setTimeout 不保证精确的时间
  3. 避免嵌套过深:使用递归 setTimeout 代替 setInterval
  4. 考虑使用 setImmediate:在 I/O 回调中优先使用

常见问题与解决方案

问题 1:process.exit() 导致资源未释放

// 问题代码
const fs = require('fs');
const stream = fs.createReadStream('large-file.txt');

stream.on('data', (chunk) => {
  console.log('读取数据');
});

process.exit(0);  // 可能导致文件未正确关闭

// 解决方案:确保资源正确释放
const fs = require('fs');
const stream = fs.createReadStream('large-file.txt');

stream.on('data', (chunk) => {
  console.log('读取数据');
});

stream.on('end', () => {
  console.log('读取完成');
  process.exit(0);
});

stream.on('error', (error) => {
  console.error('读取失败:', error);
  process.exit(1);
});

问题 2:定时器内存泄漏

// 问题代码
function createTimer() {
  setInterval(() => {
    console.log('定时任务');
  }, 1000);
}

createTimer();  // 定时器没有被清除

// 解决方案:保存定时器 ID 并在需要时清除
const timers = [];

function createTimer() {
  const timerId = setInterval(() => {
    console.log('定时任务');
  }, 1000);
  timers.push(timerId);
  return timerId;
}

const timerId = createTimer();

// 在需要时清除
setTimeout(() => {
  clearInterval(timerId);
}, 5000);

问题 3:console.log 性能问题

// 问题代码:大量日志输出
for (let i = 0; i < 100000; i++) {
  console.log(i);  // 性能很差
}

// 解决方案:减少日志输出或使用日志库
const winston = require('winston');
const logger = winston.createLogger({
  level: 'info',
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'app.log' })
  ]
});

for (let i = 0; i < 100000; i++) {
  if (i % 1000 === 0) {
    logger.info(`处理进度:${i}`);
  }
}

问题 4:全局变量冲突

// 问题代码:全局变量可能被覆盖
global.myConfig = { name: 'App' };

// 其他模块可能覆盖
global.myConfig = { name: 'Other App' };

// 解决方案:使用模块系统
// config.js
module.exports = {
  name: 'App'
};

// app.js
const config = require('./config');
console.log(config.name);

总结

本教程详细介绍了 Node.js 的全局对象和全局变量,包括 global、process、console、定时器函数等重要内容。掌握这些全局对象对于编写高效的 Node.js 应用程序至关重要。

通过本集的学习,您应该能够:

  1. 理解 Node.js 全局对象的概念
  2. 使用 global 对象管理全局变量
  3. 使用 process 对象获取进程信息和控制进程
  4. 使用 console 对象进行日志输出和调试
  5. 使用定时器函数实现延迟和周期性任务
  6. 避免常见的全局对象使用错误

在下一集中,我们将学习 Node.js 的文件系统基础,这是 Node.js 编程的核心功能之一。继续加油,您的 Node.js 技能正在不断提升!

« 上一篇 Node.js 模块系统 下一篇 » Node.js 文件系统基础