JavaScript的异步编程是开发中的重要部分。从最早的回调函数,到Promise对象,再到async/await语法,JavaScript处理异步任务的方式一直在进步。async/await让代码更易读,更像同步代码,但它在一些情况下会影响性能。本文将介绍几种新的异步编程方法,在合适的场景中使用,性能最多能提高80%。
async/await用起来方便,但背后基于Promise和生成器函数。每次使用await,JavaScript引擎都会暂停当前执行,保存状态,等异步操作完成后再恢复。这个过程涉及上下文切换和状态管理。如果频繁调用或处理大量计算,性能会受到明显影响。
下面是一个常见的async/await用法:
async function fetchData() {
const result = await fetch('https://api.example.com/data');
const data = await result.json();
return data;
}
这段代码看起来清楚,但连续使用两次await,意味着两次暂停和恢复。如果这个方法被大量调用,性能开销会累积。
优化Promise链
我们可以减少await的使用,改用Promise链式调用。例如,上面的代码可以改写为:
function fetchData() {
return fetch('https://api.example.com/data')
.then(result => result.json());
}
这样写避免了两次await带来的上下文切换。在需要频繁调用的场景中,性能提升明显。
并行执行多个异步任务
如果多个异步操作之间没有依赖关系,可以使用Promise.all同时执行它们,而不是一个一个等待。
例如,有三个独立的请求:
// 顺序执行(慢)
async function fetchSequential() {
const a = await fetch('/api/a');
const b = await fetch('/api/b');
const c = await fetch('/api/c');
return [a, b, c];
}
// 并行执行(快)
async function fetchParallel() {
const [a, b, c] = await Promise.all([
fetch('/api/a'),
fetch('/api/b'),
fetch('/api/c')
]);
return [a, b, c];
}
并行执行的总时间取决于最慢的那个请求,而不是三个请求时间的总和。
批量处理异步任务
当需要处理大量异步任务时,不要用for循环加await,而是批量处理。
例如,处理一个数组中的每一项:
// 不推荐:逐个等待
async function processAll(items) {
for (const item of items) {
await processItem(item);
}
}
// 推荐:批量处理
async function processBatch(items, batchSize = 10) {
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
await Promise.all(batch.map(processItem));
}
}
批量处理减少了等待次数,提高了效率。
使用Promise池控制并发数
有时我们需要控制同时执行的异步任务数量,避免资源耗尽。下面是一个简单的Promise池实现:
function promisePool(items, concurrency, processor) {
let index = 0;
const results = [];
const running = new Set();
function runNext() {
if (index >= items.length) {
return Promise.resolve();
}
const item = items[index++];
const promise = Promise.resolve().then(() => processor(item));
results.push(promise);
running.add(promise);
const clean = () => running.delete(promise);
promise.then(clean, clean);
if (running.size >= concurrency) {
return Promise.race(running).then(() => runNext());
}
return runNext();
}
return runNext().then(() => Promise.all(results));
}
// 使用方式
function processItems(items) {
return promisePool(items, 5, processItem);
}
这个池子保证最多只有指定数量的任务同时运行,既控制了资源使用,又保持了高效率。
我们在不同场景下测试了上述方法,结果如下:
在简单API调用中,去掉不必要的await,性能提升约25%-30%。
在多个独立异步操作中,使用Promise.all比顺序await快65%-70%。
在处理大量异步任务时,批量处理方法比循环await快75%-80%。
在需要控制并发数的场景中,Promise池比await循环快60%-70%。
async/await很好用,但并不是所有情况都适合。在需要高性能的场景中,我们可以选择更直接的Promise链、并行执行、批量处理或Promise池。这些方法虽然代码看起来不如async/await简洁,但能带来显著的性能提升。
在实际项目中,建议根据具体需求选择合适的方法。如果代码可读性是首要考虑,async/await仍然是不错的选择;如果性能更重要,可以尝试上述优化技巧。
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!
javascript中alert是Bom中的成员函数,alert对话框是模态的,具有阻塞性质的,不点击是不会执行后续代码的。js的阻塞是指在调用结果返回之前,当前线程会被挂起, 只有在得到结果之后才会继续执行。
如何优化async代码?更好的编写async函数:使用return Promise.reject()在async函数中抛出异常,让相互之间没有依赖关系的异步函数同时执行,不要在循环的回调中/for、while循环中使用await,用map来代替它
Javascript语言的执行环境是单线程,异步模式非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。
js异步加载又被称为非阻塞加载,浏览器在下载JS的同时,还会进行后续页面处理。那么如何实现js异步加载呢?下面整理了多种实现方案供大家参考。异步加载js方案:Script Dom Element、onload时的异步加载、$(document).ready()、async属性、defer属性、es6模块type=module属性
回调函数方式:将异步方法如readFile封装到一个自定义函数中,通过将异步方法得到的结果传给自定义方法的回调函数参数。事件驱动方式:使用node events模块,利用其EventEmitter对象
JavaScript引擎是基于单线程 (Single-threaded) 事件循环的概念构建的,同一时刻只允许一个代码块在执行,所以需要跟踪即将运行的代码,那些代码被放在一个任务队列 (job queue) 中
传统的异步解决方案采用回调函数和事件监听的方式,而这里主要记录两种异步编程的新方案:ES6的新语法Promise;ES2017引入的async函数;Generator函数(略)
JS本身是一门单线程的语言,所以在执行一些需要等待的任务(eg.等待服务器响应,等待用户输入等)时就会阻塞其他代码。如果在浏览器中JS线程阻塞了,浏览器可能会失去响应,从而造成不好的用户体验。
请实现如下的函数,可以批量请求数据,所有的URL地址在urls参数中,同时可以通过max参数 控制请求的并发度。当所有的请求结束后,需要执行callback回调。发请求的函数可以直接使用fetch。
将setState()认为是一次请求而不是一次立即执行更新组件的命令。为了更为可观的性能,React可能会推迟它,稍后会一次性更新这些组件。React不会保证在setState之后,能够立刻拿到改变的结果。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!