Js实战技巧:提升代码质量与性能的十个方法

更新日期: 2025-11-04 阅读: 26 标签: 性能

很多教程都在重复基础内容,比如异步函数和手写 Promise。如果你已经熟悉这些知识,下面这十个高级技巧可以帮助你更深入地理解 JavaScript 。这些方法来自实际项目经验,能够解决真实问题,比如内存泄漏、性能瓶颈和资源管理。

这些技巧曾经在实际项目中带来显著改进:

  • 减少线上服务内存泄漏 38%

  • 降低数据库成本 60%

  • 提升批处理速度 3.2 倍

无论是不被处理的异步操作,还是容易出问题的连接池,这些方法都能帮助你构建更稳定的系统。


1. 使用 void 处理立即执行的异步函数

立即执行的异步函数可能会返回一个未被处理的 Promise,导致内存泄漏或未捕获的错误。使用 void 可以明确表示我们不关心这个 Promise 的结果。

// 不推荐:返回的 Promise 没有被处理
(async () => {
  await initializeApp();
})();

// 推荐:使用 void 明确丢弃返回值
void (async () => {
  await initializeApp();
})();

这种方法适用于启动时的异步任务,比如加载配置或初始化缓存。使用 void 可以让代码意图更清晰,避免工具提示未处理的 Promise。


2. 使用 Performance api 精确测量时间

console.time 适合粗略测量,但如果需要更精确的时间数据,可以使用 Performance API。

const measureAsync = async (name, fn) => {
  performance.mark(`${name}-start`);
  try {
    return await fn();
  } finally {
    performance.mark(`${name}-end`);
    performance.measure(name, `${name}-start`, `${name}-end`);
    const [entry] = performance.getEntriesByName(name);
    console.log(`⏱️ ${name}: ${entry.duration.toFixed(3)}ms`);
    performance.clearMarks();
  }
};

// 使用示例
await measureAsync("DatabaseTransaction", () =>
  db.transaction(complexQuery)
);

这种方法可以在浏览器的性能面板中查看详细数据,适合测量数据库操作或外部接口调用。


3. 使用 AbortController 取消异步任务

AbortController 不仅可以用于 fetch 请求,还可以取消任何异步任务。

const createCancellablePool = (promises, signal) => {
  return Promise.all(
    promises.map(
      p =>
        new Promise((resolve, reject) => {
          signal.addEventListener("abort", () =>
            reject(new domException("Cancelled", "AbortError"))
          );
          p.then(resolve).catch(reject);
        })
    )
  );
};

// 使用示例
const controller = new AbortController();
setTimeout(() => controller.abort(), 2000);

await createCancellablePool(
  [analyticssync(), cacheHydration()],
  controller.signal
);

这在用户切换页面时非常有用,可以取消不需要的异步任务,节省资源。


4. 使用异步生成器处理大量数据

一次性加载大量数据可能导致内存问题。使用异步生成器可以按需处理数据。

async function* streamResults(urls) {
  for (const url of urls) {
    const response = await fetch(url);
    yield response.json();
  }
}

// 使用示例
const videoStream = streamResults(videoUrls);

for await (const video of videoStream) {
  if (shouldStopProcessing(video)) break;
  renderPreview(video);
}

这种方法适合处理大量数据,比如日志文件或视频元信息,内存占用更稳定。


5. 使用 TypedArray 处理二进制数据

处理二进制数据时,TypedArray 比普通数组更高效。

const mergeBuffers = (buffers) => {
  const total = buffers.reduce((sum, b) => sum + b.byteLength, 0);
  const result = new Uint8Array(total);

  let offset = 0;
  buffers.forEach(buffer => {
    result.set(new Uint8Array(buffer), offset);
    offset += buffer.byteLength;
  });

  return result.buffer;
};

适用于 WebAssembly、WebGL 或 WebSocket 等场景。


6. 使用 Error cause 链接错误信息

在复杂的异步操作中,错误信息可能不够详细。使用 Error cause 可以保留原始错误信息。

async function processOrder() {
  try {
    await validatePayment();
  } catch (err) {
    throw new Error("Payment failed", { cause: err });
  }
}

try {
  await processOrder();
} catch (e) {
  console.error("Root cause:", e.cause);
}

这样可以在日志中看到完整的错误链,便于排查问题。


7. 安全枚举对象属性

直接使用 for...in 遍历对象可能意外访问到原型链上的属性。使用属性描述符可以避免这个问题。

const getSafeKeys = (obj) => {
  return Object.entries(Object.getOwnPropertyDescriptors(obj))
    .filter(([_, desc]) => desc.enumerable)
    .map(([key]) => key);
};

// 使用示例
const safeDict = Object.create(null);
safeDict.data = "test";
console.log(getSafeKeys(safeDict)); // ["data"]

这在处理外部数据时特别重要,可以避免原型污染。


8. 使用 Promise 池控制并发数量

一次性发送大量请求可能压垮服务。使用 Promise 池可以限制并发数量。

class PromisePool {
  constructor(concurrency) {
    this.concurrency = concurrency;
    this.running = 0;
    this.queue = [];
  }

  async run(task) {
    return new Promise((resolve, reject) => {
      const execute = async () => {
        this.running++;
        try {
          resolve(await task());
        } catch (err) {
          reject(err);
        } finally {
          this.running--;
          this.next();
        }
      };

      this.queue.push(execute);
      this.next();
    });
  }

  next() {
    while (this.queue.length && this.running < this.concurrency) {
      this.queue.shift()();
    }
  }
}

// 使用示例
const pool = new PromisePool(3);
await pool.run(() => generateReport());

这可以保护数据库或第三方服务不被过多请求压垮。


9. 使用 Proxy 观察 Promise 状态

在 UI 中,我们经常需要显示异步操作的状态。使用 Proxy 可以直接在 Promise 上获取状态信息。

function trackPromise(promise) {
  const state = {
    status: "pending",
    value: null
  };

  const proxy = new Proxy(promise, {
    get(target, prop) {
      if (prop === "status") return state.status;
      if (prop === "value") return state.value;
      return Reflect.get(target, prop);
    }
  });

  promise
    .then(result => {
      state.status = "fulfilled";
      state.value = result;
    })
    .catch(() => {
      state.status = "rejected";
    });

  return proxy;
}

// 使用示例
const dataPromise = trackPromise(fetch("/api/data"));

这样不需要额外维护状态变量,可以直接从 Promise 获取状态。


10. 使用 WeakRef 实现自动清理的缓存

缓存是常见的优化手段,但容易导致内存泄漏。使用 WeakRef 可以在对象被垃圾回收时自动清理缓存。

class TemporaryCache {
  constructor() {
    this.cache = new Map();
    this.cleanup = new FinalizationRegistry((key) => {
      this.cache.delete(key);
    });
  }

  set(key, value) {
    this.cache.set(key, new WeakRef(value));
    this.cleanup.register(value, key, value);
  }

  get(key) {
    const ref = this.cache.get(key);
    return ref?.deref();
  }
}

// 使用示例
const cache = new TemporaryCache();
cache.set("user:123", heavyUserObject);

当缓存的对象不再被使用时,缓存项会自动删除,适合大对象的短期缓存。


总结

这些技巧展示了 Js 从脚本语言到系统语言的演进:

  • 使用 Performance API 获取精确时间

  • 使用 AbortController 取消异步任务

  • 使用 WeakRef 管理内存

  • 使用 Error cause 追踪错误来源

  • 使用 Promise 池控制并发

  • 使用 TypedArray 处理二进制数据

  • 安全枚举对象属性

  • 使用 Proxy 观察 Promise 状态

  • 使用异步生成器处理大量数据

  • 使用 void 明确丢弃 Promise 结果

不需要一次性应用所有方法,根据实际需求选择合适的技巧,就能显著提升代码质量和系统性能。

本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/article/detial/13135

提高js加载速度,实现js无阻塞加载方式,高性能的加载执行JavaScript

为解决JS加载速度慢,采用js的延时加载,和动态加载。由于js的堵塞特性,当浏览器在加载javascript代码时,不能同时做其他任何事情,如果javascript执行时间越久,浏览器等待响应的时间就越久。

如何提高CSS性能?CSS优化、提高性能提升总汇

如何提高CSS性能,根据页面的加载性能和CSS代码性能,主要表现为: 加载性能 (主要是从减少文件体积,减少阻塞加载,提高并发方面入手),选择器性能,渲染性能,可维护性。

前端性能优化_css加载会造成哪些阻塞现象?

css的加载是不会阻塞DOM的解析,但是会阻塞DOM的渲染,会阻塞link后面js语句的执行。这是由于浏览器为了防止html页面的重复渲染而降低性能,所以浏览器只会在加载的时候去解析dom树,然后等在css加载完成之后才进行dom的渲染以及执行后面的js语句。

2018 前端性能检查表

性能十分重要。然而,我们真的知道性能瓶颈具体在哪儿吗?是执行复杂的 JavaScript,下载缓慢的 Web 字体,巨大的图片,还是卡顿的渲染?研究摇树(Tree Shaking),作用域提升(Scope Hoisting)

高性能Javascript总结

Js高性能总结:加载和运行、数据访问、DOM编程、算法和流程控制、响应接口、Ajax 异步JavaScript和XML、编程实践...

优化网站性能规则_前端性能优化策略【网络加载、页面渲染】

前端网站性能优化规则:网络加载类、页面渲染类。包括:减少 HTTP 资源请求次数、减小 HTTP 请求大小、避免页面中空的 href 和 src、合理设置 Etag 和 Last-Modified、使用可缓存的 AJAX、减少 DOM 元素数量和深度等

前端性能的本质是什么?

性能一直以来是前端开发中非常重要的话题。随着前端能做的事情越来越多,浏览器能力被无限放大和利用:从 web 游戏到复杂单页面应用,从 NodeJS 服务到 web VR/AR 和数据可视化,前端工程师总是在突破极限

BigPipe_高性能流水线页面技术

BigPipe是一个重新设计的基础动态网页服务体系。大体思路是,分解网页成叫做Pagelets的小块,然后通过Web服务器和浏览器建立管道并管理他们在不同阶段的运行。这是类似于大多数现代微处理器的流水线执行过程:多重指令管线通过不同的处理器执行单元,以达到性能的最佳。

用CSS开启硬件加速来提高网站性能

你知道我们可以在浏览器中用css开启硬件加速,使GPU (Graphics Processing Unit) 发挥功能,从而提升性能吗?现在大多数电脑的显卡都支持硬件加速。鉴于此,我们可以发挥GPU的力量,从而使我们的网站或应用表现的更为流畅。

原生js实现懒加载并节流

像淘宝网站等,页面中有着大量图片,一次性全部加载这些图片会使浏览器发送大量请求和造成浪费。采用懒加载技术,即用户浏览到哪儿,就加载该处的图片。这样节省网络资源、提升用户体验、减少服务器压力。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!