存在链式依赖的do..while()循环中如何避免使用await
方案1:局部禁用ESLint规则(改动最小)
no-await-in-loop规则的设计初衷是避免开发者无意识将可并行的异步操作串行执行,浪费IO性能。你的场景中必须依赖前一次调用返回的nextAfter游标才能发起下一次请求,属于合理的串行异步场景,完全可以局部禁用该规则,原有逻辑无需任何修改:
async computeAllData(start, range, wait, buckets, accumulator) { let nextAfter = false; do { // eslint-disable-next-line no-await-in-loop nextAfter = await this.computeOne( start, range, wait, buckets, accumulator, nextAfter ); } while (nextAfter); }
方案2:递归实现(无需修改ESLint规则)
如果不想调整ESLint规则,可以用递归逻辑完全等价替换原有do...while逻辑,不会触发循环内使用await的校验:
async computeAllData(start, range, wait, buckets, accumulator, nextAfter = false) { const newNextAfter = await this.computeOne( start, range, wait, buckets, accumulator, nextAfter ); // 等价于原do...while的终止判断 if (newNextAfter) { return this.computeAllData(start, range, wait, buckets, accumulator, newNextAfter); } }
该实现和原有逻辑行为完全一致:首次执行会先调用一次computeOne,拿到游标后判断是否需要继续执行,直到游标为空终止。普通分页场景下递归深度不会超出JS调用栈限制,无需担心栈溢出问题。
方案3:Promise链式调用(适配超深层分页场景)
如果你的数据量极大,递归深度可能超过调用栈限制,可以用链式Promise实现,本质是自动迭代生成Promise链:
computeAllData(start, range, wait, buckets, accumulator) { // 初始Promise,对应do...while首次执行 let chain = Promise.resolve(false); const runNext = (nextAfter) => { if (!nextAfter) return; return this.computeOne(start, range, wait, buckets, accumulator, nextAfter).then(runNext); }; return chain.then(runNext); }
该方案没有递归调用栈,也没有循环内await,适配任意深度的分页场景。
内容的提问来源于stack exchange,提问作者Arnaud Dev
相关产品推荐
相关产品推荐

