使用 queuemicrotask 或 settimeout 将 set 遍历拆分为多个微任务或宏任务,以避免阻塞主线程。具体做法是维护一个迭代器,每次处理固定数量的元素后调度下一次执行,直到遍历完成。

如何基于迭代器实现非阻塞的 Set 遍历
通过调用 set[Symbol.iterator]() 获取迭代器,在循环中手动调用 next() 并检查 done 状态。当处理完一批数据后,使用 queueMicrotask 调度下一批,确保 UI 渲染不被阻塞。

function splitSetTraversal(set, batchSize = 100) {
const iterator = set[Symbol.iterator]();
let batch = [];
function processBatch() {
for (let i = 0; i < batchSize; i++) {
const { done, value } = iterator.next();
if (done) return;
batch.push(value);
}
// 假设这里有一个需要批量处理的函数
console.log('Processed:', batch);
batch = [];
queueMicrotask(processBatch);
}
queueMicrotask(processBatch);
}
const mySet = new Set(Array.from({ length: 10000 }, (_, i) => i));
splitSetTraversal(mySet); // 预期:每批处理100个元素,分100次执行,不阻塞UI
如何处理 Set 中的异步操作而不阻塞
如果遍历过程中涉及异步操作(如网络请求),应使用 async/await 配合 setTimeout 进行拆分。每次处理完一个元素后,等待下一个宏任务再处理下一个,防止长时间占用事件循环。
立即学习“Java免费学习笔记(深入)”;

async function asyncSplitSetTraversal(set, delay = 0) {
const iterator = set[Symbol.iterator]();
let result = [];
function next() {
const { done, value } = iterator.next();
if (done) return Promise.resolve(result);
// 模拟异步操作
const processed = value * 2;
result.push(processed);
if (delay > 0) {
return new Promise(resolve => setTimeout(resolve, delay)).then(next);
}
return next();
}
return next();
}
const mySet = new Set([1, 2, 3, 4, 5]);
asyncSplitSetTraversal(mySet, 10).then(res => console.log('Result:', res)); // 预期:每10ms处理一个元素,最终输出 [2, 4, 6, 8, 10]
当 Set 为空时遍历行为如何
当传入空的 Set 时,迭代器的 next() 第一次调用即返回 { done: true, value: undefined },因此不会进入任何处理批次,直接结束遍历,无副作用。


















