您现在的位置是:网站首页 > 代码优化技巧文章详情

代码优化技巧

Node.js作为高效的JavaScript运行时,代码优化直接影响性能与可维护性。以下是针对异步控制、内存管理、算法选择等场景的具体实践方案。

异步流程优化

避免回调地狱是Node.js优化的首要任务。util.promisify可将回调函数快速转为Promise:

const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);

async function processFiles() {
  try {
    const data = await readFile('config.json');
    return JSON.parse(data);
  } catch (err) {
    console.error('文件处理失败', err);
  }
}

对于并行任务,优先使用Promise.allSettled而非Promise.all

const API_CALLS = [
  fetchUserData(),
  fetchConfig(),
  fetchPermissions()
];

const results = await Promise.allSettled(API_CALLS);
const successfulData = results
  .filter(r => r.status === 'fulfilled')
  .map(r => r.value);

内存泄漏防范

闭包不当使用是常见泄漏源。以下代码会导致timer持续持有作用域:

function createLeak() {
  const hugeArray = new Array(1e6).fill('*');
  setInterval(() => {
    console.log(hugeArray.length); // 闭包持有hugeArray
  }, 1000);
}

改用WeakMap解决:

const wm = new WeakMap();
function noLeak() {
  const data = { largeData: new Array(1e6) };
  wm.set(data, 'metadata');
  setInterval(() => {
    console.log(wm.get(data)); // 弱引用可被GC回收
  }, 1000);
}

算法时间复杂度优化

数据库查询时常见O(n²)问题:

// 低效写法
async function getUserWithPosts() {
  const users = await User.findAll();
  return Promise.all(users.map(async user => {
    const posts = await Post.findAll({ where: { userId: user.id } });
    return { ...user.toJSON(), posts };
  }));
}

改为批量查询降低复杂度:

// 优化版本
async function optimizedQuery() {
  const users = await User.findAll();
  const userIds = users.map(u => u.id);
  const allPosts = await Post.findAll({ 
    where: { userId: userIds },
    attributes: ['id', 'userId', 'content']
  });
  
  return users.map(user => ({
    ...user.toJSON(),
    posts: allPosts.filter(p => p.userId === user.id)
  }));
}

流式处理大文件

传统文件读取方式会导致内存暴涨:

// 危险操作
fs.readFile('huge.log', (err, data) => {
  if (err) throw err;
  processData(data); // 一次性加载到内存
});

改用流处理:

const { pipeline } = require('stream');
const zlib = require('zlib');

pipeline(
  fs.createReadStream('huge.log'),
  zlib.createGzip(), // 压缩中转
  fs.createWriteStream('huge.log.gz'),
  (err) => {
    if (err) console.error('处理失败', err);
  }
);

缓存策略实现

内存缓存基础实现:

class SimpleCache {
  constructor(ttl = 60) {
    this.store = new Map();
    this.ttl = ttl * 1000;
  }

  set(key, value) {
    this.store.set(key, {
      timestamp: Date.now(),
      value
    });
  }

  get(key) {
    const entry = this.store.get(key);
    if (!entry) return null;
    
    if (Date.now() - entry.timestamp > this.ttl) {
      this.store.delete(key);
      return null;
    }
    return entry.value;
  }
}

事件循环优化

耗时任务应分解:

// 阻塞事件循环
function syncTask() {
  for(let i=0; i<1e8; i++) {
    heavyCalculation(i);
  }
}

// 优化方案
async function asyncTask() {
  let i = 0;
  const CHUNK_SIZE = 1e6;
  
  function nextChunk() {
    while(i < 1e8 && i % CHUNK_SIZE !== 0) {
      heavyCalculation(i++);
    }
    
    if (i < 1e8) {
      setImmediate(nextChunk);
    }
  }
  
  nextChunk();
}

对象复用策略

频繁创建对象触发GC:

// 低效写法
function processRequest(req) {
  const metrics = {
    start: Date.now(),
    method: req.method
  };
  // ...处理逻辑
  return metrics;
}

改为对象池:

const metricPool = {
  allocate() {
    return this._pool.pop() || { 
      start: 0, 
      method: '' 
    };
  },
  free(obj) {
    this._pool.push(obj);
  },
  _pool: []
};

function optimizedHandler(req) {
  const metrics = metricPool.allocate();
  metrics.start = Date.now();
  metrics.method = req.method;
  
  // ...处理逻辑
  
  metricPool.free(metrics);
}

错误处理优化

避免重复实例化错误对象:

// 常规写法
app.get('/api', (req, res, next) => {
  try {
    validateInput(req.query);
  } catch (err) {
    next(new Error('验证失败')); // 每次新建Error实例
  }
});

// 优化方案
const VALIDATION_ERROR = Object.freeze(
  new Error('验证失败')
);

app.get('/api', (req, res, next) => {
  try {
    validateInput(req.query);
  } catch (err) {
    next(VALIDATION_ERROR); // 复用错误实例
  }
});

依赖加载优化

动态加载非必要模块:

// 传统写法
const PDFGenerator = require('heavy-pdf-lib');

router.post('/report', async (req, res) => {
  const pdf = new PDFGenerator();
  // ...生成PDF
});

// 按需加载
router.post('/report', async (req, res) => {
  const { default: PDFGenerator } = await import('heavy-pdf-lib');
  const pdf = new PDFGenerator();
});

日志记录优化

同步日志影响性能:

// 问题代码
function logRequest(req) {
  fs.appendFileSync('access.log', `${req.url}\n`);
}

改用WritableStream:

const { Writable } = require('stream');
const logStream = new Writable({
  write(chunk, _, callback) {
    fs.appendFile('access.log', chunk, callback);
  }
});

function logOptimized(req) {
  logStream.write(`${req.url}\n`);
}

上一篇: 负载测试

下一篇: 调试工具使用

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步