首页app攻略async await详解 async await 并行

async await详解 async await 并行

圆圆2025-07-13 17:01:22次浏览条评论

工件处理适用于无依赖,使用promise.all()或promise.allsettled()实现;串行处理用于需顺序执行的场景,可通过循环或减少链式调用完成;有限并行控制可借助任务队列和并行计数器效率与资源占用。

async函数中的并行与串行控制

在异步函数的世界里,任务与串行控制是我们日常编码中心血管的考量。说起来简单,任务就是让多个任务同时起来,争取最快的总完成时间;而串口让一个接一个任务地执行,确保每一步都按序完成,这通常是为了资源管理、依赖关系或者避免某些后果。选择哪种方式,往往取决于你手头任务的特性:是追求最终的吞吐量,需要严格的执行顺序和资源约束。解决方案

处理async函数中的工具与串行,核心位于对Promise的运用。

实现工具:

最直接的方式是利用 Promise.all()。当你有一组相互独立、没有后续依赖的异步任务时,把它们打包成 Promise 队列,然后丢给 Promise.all()。它会所有 Promise 等待都成功解决后,返回一个包含所有结果的队列。这就像你同时启动了多台机器,它们各自干活,最后你等着所有机器都出结果。async function fetchMultipleDataParallel() { const urls = ['/api/data1', '/api/data2', '/api/data3']; try { // 假设 fetchData 是一个返回 Promise 的异步函数 const results = wait Promise.all(urls.map(url =gt; fetchData(url))); console.log('所有数据获取完成:', results); 返回结果; } catch (error) { console.error('设备获取数据时发生错误:', error); // Promise.all 的一个特点是,只要有一个 Promise 失败,它就会立即拒绝抛出错误; }}登录后复制

如果你不关心所有任务是否都成功,或者想知道每个任务的最终状态(成功还是失败),Promise.allSettled() 是更好的选择。它会等待所有 Promise 都“落定”(已解决,即成功或失败),然后返回一个包含每个 Promise状态和结果(或原因)的对象数组。这在处理一组可能失败的任务时特别有用,你不想因为一个任务的失败而整个流程。

实现串行:

最复杂的串行控制就是在一个循环中使用await关键字。当你需要确保前一个异步操作完成后,下一个才能开始时,这种方式非常适用。

async function processTasksSequentially() { const taskIds = [101, 102, 103]; const results = []; for (const id of taskIds) { try { // 假设 processTask 是一个异步函数 const result = wait processTask(id); // 等待当前任务完成 results.push(result); console.log(`任务 ${id} 完成,结果:`, result); } catch (error) { console.error(`任务 ${id} 失败:`, error); // 可以选择继续或中断 } } console.log('所有任务串行处理完成:', results);返回结果;}登录后复制

另一种优雅的串行方式是使用 Array.prototype.reduce 来链执行 Promise。这在处理一系列相互依赖的操作时尤其强大。async function chainDependentOperations() { const Operations = [ async (data) =gt; { /* 操作1 */ return data 1; }, async (data) =gt; { /* 操作 2 */ 返回数据 * 2; }, async (data) =gt; { /* 操作 3 */ 返回数据 - 5; } ]; const FinalResult = wait Operations.reduce(async (previousPromise, currentOperation) =gt; { const previousResult = wait previousPromise; // 等待上一个操作完成 return currentOperation(previousResult); //执行当前操作并返回新的 Promise }, Promise.resolve(0)); // 初始值,可以是任意 Promise.resolve(initialValue) console.log('链式操作最终结果:', FinalResult); // 预期输出 (0 1)*2-5 = -3 return FinalResult;}登录后复制

这种reduce 的实现方式,将上一个操作的结果作为下一个操作的输入,非常适合数据流动的场景。异步任务何时处理?

这是一个常见的决策点。我的经验是,当你考虑异步任务之间没有任何数据依赖或执行顺序上的强制要求时,就应该异步。

想象一下,你要从三个不同的微服务中提取数据,这三份数据各自独立,谁先回来都没关系,只要最后都拿到了就行。这个时候,用 Promise.all去空闲请求是最高效的。

另一个考虑因素是用户体验。如果你的应用程序需要加载多张图片、多个API数据来填充页面,让它们加载可以显着减少用户的等待时间,提升读取性能。用户通常不会等待一个又一个的请求完成。

然而,占用总是不是万能药。它会占用更多的系统资源,比如网络带宽、CPU或内存。如果你在短时间内发起几百个疯狂请求,可能会导致服务器过载、浏览器崩溃,被API限流。所以,或者抓更多一种策略优化,而不是无脑应用。你需要评估任务的性质、可用的资源以及潜在的风险。如何在疯狂任务中缓慢地处理错误和部分成功?

抓任务的错误处理是个棘手的问题。Promise.all()的“全有或全无”特性,即一旦其中一个 Promise 拒绝,整个 Promise.all 就会立即拒绝,并且不会等待其他此时执行的 Promise。对于一些严格要求所有任务都成功的场景很合适,但很多时候我们希望即使有任务失败,也能知道哪些失败了,哪些成功了,并继续处理成功的部分。

这个时候,Promise.allSettled()就派上用场了。它返回的结果是一个数组,每个元素都是一个对象,包含状态('已完成'或'拒绝')和值(成功时的结果)或原因(失败时的错误)。

async function fetchWithPartialSuccess() { const urls = [ '/api/good-data', '/api/bad-data-will-fail', '/api/another-good-data' ]; const results = wait Promise.allSettled(urls.map(url =gt; fetchData(url))); results.forEach((result,index) =gt; { if (result.status) === 'fulfilled') { console.log(`URL ${urls[index]} 成功:`, result.value); // 可以继续处理成功的数据 } else { console.error(`URL ${urls[index]} 失败:`, result.reason); // 记录错误,或进行回滚等操作 } }); // 你甚至可以过滤出成功的结果 const successResults = results .filter(r =gt; r.status === '完成') .map(r =gt; r.value); console.log('成功获取的数据:', successResults); //或者查找所有失败的原因 const failedReasons = results .filter(r =gt; r.status === 'rejected') .map(r =gt; r.reason); console.log('失败的原因:', failedReasons);}登录后复制

通过Promise.allSettled(),你可以对每个任务的最终状态进行细粒度的控制和处理,而不必因为一个失败而放弃整个批次。

另一种策略是在映射每个 Promise 时,就用 try...catch 包裹住,让每个单独的 Promise 总是解决(fulfilled),即使内部发生错误。这样 Promise.all() 就能正常运行,你会在结果队列中错误得到的对象是实际数据。

async function fetchAndHandleErrorsIndividually() { const urls = ['/api/data1', '/api/data-fail', '/api/data3']; const Promise = urls.map(async (url) =gt; { try { const data = wait fetchData(url); return { status: '成功', data }; } catch (error) { return { status: 'error', error: error.message, url }; } }); const results = wait Promise.all(promises); // 这里的 Promise.all 不会拒绝 results.forEach(item =gt; { if (item.status === 'success') { console.log('成功获取:', item.data); } else { console.error(`从 ${item.url} 获取失败:`,项目.错误); } });}登录后复制

这种方式的优点是,Promise.all不会因为单个错误而中断,但你需要自己在返回的数据结构中处理错误信息。如何实现对异步任务的有限并发控制?

有时,我们既想利用一个提升效率,又同时启动过多任务导致资源拖延或被有限流。其次,有限并行控制就极其重要。这就像你有一条生产线,可以同时处理3个订单,但不能更多。

实现有限并发的一种常见模式是使用一个“队列任务队列”和“工人池”。你可以维护一个正在执行的任务分量,当达到最大并发数时,新的任务就等待进入队列。当有任务完成时,就从队列中取出下一个任务开始执行。

下面是一个简化的实现思路:class ConcurrencyLimiter { constructor(limit) { this.limit = limit; // 最大并发数 this.running = 0; // 当前正在运行的任务数 this.queue = []; // 等待执行的任务队列 } /** * 添加一个异步任务到队列 * @param {Function} taskFn - 返回 Promise 的异步函数 * @returns {Promise} - 任务执行的结果Promise */ add(taskFn) { return new Promise((resolve,reject) =gt; { this.queue.push({ taskFn,resolve,reject }); this.runNext(); }); } async runNext() { if (this.running gt;= this.limit || this.queue.length === 0) { return; // 达到极限或没有任务了 } this.running ; const { taskFn, 解决, 拒绝 } = this.queue.shift(); // 取出队列中的第一个任务 try { const result = wait taskFn(); // 执行任务resolve(result); } catch (error) {reject(error); }finally { this.running--; // 任务完成,无论成功失败,减少运行计数 this.runNext(); // 尝试运行下一个任务 } }}// 示例:async functionsimulateTask(id,duration) { console.log(`任务 ${id} 开始,预计运行 ${duration}ms`); return new Promise(resolve =gt; setTimeout(() =gt; { console.log(`任务 ${id} 完成`);resolve(`任务 ${id} 的结果`); },持续时间));}async function runLimitedConcurrency() { const limiter = new ConcurrencyLimiter(2); // 最大线程数设为2 consttasks = [ limiter.add(() =gt;simulateTask(1, 1000)),

limiter.add(() =gt;simulateTask(2, 500)), limiter.add(() =gt;simulateTask(3, 1200)), limiter.add(() =gt;simulateTask(4, 800)), limiter.add(() =gt;simulateTask(5, 600)),]; console.log('所有任务已提交'); const results = wait Promise.all(tasks); // 等待所有任务完成 console.log('所有任务(有限并发)完成:', results);}runLimitedConcurrency();登录后复制

这个ConcurrencyLimiter类就是一种简单的有限并发控制机制。保证在任意给定时间点,最多限制一个任务只在同时执行。当一个任务完成时,它会立即检查队列中是否有等待的任务,并启动下一个。这处理量输入/输出 密集型任务(如网络请求)时非常实用,既能利用毛线优势,又能避免资源枯竭。

以上就是异步函数中的毛线与串行控制的详细内容,更多请关注乐哥常识网其他相关文章!

async函数中的并
土味tsp 土味猫出击:SPX6900暴跌与Peanut松鼠是否陷身模因币泥潭?
相关内容
发表评论

游客 回复需填写必要信息