很多教程都在重复基础内容,比如异步函数和手写 Promise。如果你已经熟悉这些知识,下面这十个高级技巧可以帮助你更深入地理解 JavaScript 。这些方法来自实际项目经验,能够解决真实问题,比如内存泄漏、性能瓶颈和资源管理。
这些技巧曾经在实际项目中带来显著改进:
减少线上服务内存泄漏 38%
降低数据库成本 60%
提升批处理速度 3.2 倍
无论是不被处理的异步操作,还是容易出问题的连接池,这些方法都能帮助你构建更稳定的系统。
立即执行的异步函数可能会返回一个未被处理的 Promise,导致内存泄漏或未捕获的错误。使用 void 可以明确表示我们不关心这个 Promise 的结果。
// 不推荐:返回的 Promise 没有被处理
(async () => {
await initializeApp();
})();
// 推荐:使用 void 明确丢弃返回值
void (async () => {
await initializeApp();
})();这种方法适用于启动时的异步任务,比如加载配置或初始化缓存。使用 void 可以让代码意图更清晰,避免工具提示未处理的 Promise。
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)
);这种方法可以在浏览器的性能面板中查看详细数据,适合测量数据库操作或外部接口调用。
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
);这在用户切换页面时非常有用,可以取消不需要的异步任务,节省资源。
一次性加载大量数据可能导致内存问题。使用异步生成器可以按需处理数据。
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);
}这种方法适合处理大量数据,比如日志文件或视频元信息,内存占用更稳定。
处理二进制数据时,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 等场景。
在复杂的异步操作中,错误信息可能不够详细。使用 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);
}这样可以在日志中看到完整的错误链,便于排查问题。
直接使用 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"]这在处理外部数据时特别重要,可以避免原型污染。
一次性发送大量请求可能压垮服务。使用 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());这可以保护数据库或第三方服务不被过多请求压垮。
在 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 获取状态。
缓存是常见的优化手段,但容易导致内存泄漏。使用 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 结果
不需要一次性应用所有方法,根据实际需求选择合适的技巧,就能显著提升代码质量和系统性能。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
为解决JS加载速度慢,采用js的延时加载,和动态加载。由于js的堵塞特性,当浏览器在加载javascript代码时,不能同时做其他任何事情,如果javascript执行时间越久,浏览器等待响应的时间就越久。
如何提高CSS性能,根据页面的加载性能和CSS代码性能,主要表现为: 加载性能 (主要是从减少文件体积,减少阻塞加载,提高并发方面入手),选择器性能,渲染性能,可维护性。
css的加载是不会阻塞DOM的解析,但是会阻塞DOM的渲染,会阻塞link后面js语句的执行。这是由于浏览器为了防止html页面的重复渲染而降低性能,所以浏览器只会在加载的时候去解析dom树,然后等在css加载完成之后才进行dom的渲染以及执行后面的js语句。
性能十分重要。然而,我们真的知道性能瓶颈具体在哪儿吗?是执行复杂的 JavaScript,下载缓慢的 Web 字体,巨大的图片,还是卡顿的渲染?研究摇树(Tree Shaking),作用域提升(Scope Hoisting)
Js高性能总结:加载和运行、数据访问、DOM编程、算法和流程控制、响应接口、Ajax 异步JavaScript和XML、编程实践...
前端网站性能优化规则:网络加载类、页面渲染类。包括:减少 HTTP 资源请求次数、减小 HTTP 请求大小、避免页面中空的 href 和 src、合理设置 Etag 和 Last-Modified、使用可缓存的 AJAX、减少 DOM 元素数量和深度等
性能一直以来是前端开发中非常重要的话题。随着前端能做的事情越来越多,浏览器能力被无限放大和利用:从 web 游戏到复杂单页面应用,从 NodeJS 服务到 web VR/AR 和数据可视化,前端工程师总是在突破极限
BigPipe是一个重新设计的基础动态网页服务体系。大体思路是,分解网页成叫做Pagelets的小块,然后通过Web服务器和浏览器建立管道并管理他们在不同阶段的运行。这是类似于大多数现代微处理器的流水线执行过程:多重指令管线通过不同的处理器执行单元,以达到性能的最佳。
你知道我们可以在浏览器中用css开启硬件加速,使GPU (Graphics Processing Unit) 发挥功能,从而提升性能吗?现在大多数电脑的显卡都支持硬件加速。鉴于此,我们可以发挥GPU的力量,从而使我们的网站或应用表现的更为流畅。
像淘宝网站等,页面中有着大量图片,一次性全部加载这些图片会使浏览器发送大量请求和造成浪费。采用懒加载技术,即用户浏览到哪儿,就加载该处的图片。这样节省网络资源、提升用户体验、减少服务器压力。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!