JavaScript的秘密生活:Async Generator

发布: (2026年2月17日 GMT+8 09:04)
4 分钟阅读
原文: Dev.to

Source: Dev.to

如何使用 for await...of 处理数据流。

Timothy 正在揉搓他的太阳穴。屏幕上是一段看起来像在进行一场无望战斗的函数。

async function getAllUsers() {
    let url = '/api/users?page=1';
    const allUsers = [];

    while (url) {
        const response = await fetch(url);
        const data = await response.json();

        // Add this page's users to our big list
        allUsers.push(...data.users);

        // Prepare for the next loop... if there is one
        url = data.nextPage; 
    }

    return allUsers;
}

“我想把所有用户数据都下载下来,”Timothy 向 Margaret 解释道。“可是有 50,000 条用户记录。如果我等所有页面都下载完才开始处理,用户要等 20 秒。感觉……卡住了。”

Margaret 点点头。“你把 Stream 当成 Bucket 来使用,”她说。
“你想把每一滴水都收集起来才让人喝,”她继续道。“为什么不直接让他们从水管里喝呢?”

混合体

Margaret 在白板上写下了一种新语法。它结合了语言中最强大的两个关键字。

async function* fetchUsers() { ... }

AsyncGenerator 相遇。async 让我们可以等待网络请求,* 让我们一次产出一块数据。

她重写了 Timothy 的代码,并加入了安全网。

async function* fetchUsers() {
    let url = '/api/users?page=1';

    while (url) {
        try {
            const response = await fetch(url);
            const data = await response.json();

            // Instead of building a massive array, we deliver this page immediately
            for (const user of data.users) {
                yield user;
            }

            url = data.nextPage;
        } catch (error) {
            console.error("Stream interrupted", error);
            return; // Stop the stream safely
        }
    }
}

魔法循环(for await...of

“这就是魔法发生的地方,”Margaret 说。“我们需要一个会等待的循环。”

她写下了消费代码:

const userStream = fetchUsers();

for await (const user of userStream) {
    console.log("Processing:", user.name);
    // This loop automatically PAUSES while the next page downloads!
}

Timothy 观察着控制台的模拟。

  • 循环立即打印出 10 位用户。
  • 循环 暂停(网络正在获取第 2 页)。
  • 循环恢复并再打印出 10 位用户。

“暂停是看不见的,”Timothy 低声说。

“正是如此,”Margaret 回答。“循环内部的代码并不知道它在等待。它只是在请求下一个用户,而 JavaScript 负责处理暂停。你不是在处理 Memory Snapshot,而是在处理 Time。”

紧急刹车

“还有一点,”Margaret 降低声音补充道。“在真实世界里,流可能是无止境的。有时用户会在你完成之前离开页面。”

“我该怎么办?”

“使用 AbortController,”她说。“它可以让你切断水管。一定要让你的流能够被停止。”

结论

Timothy 删除了 allUsers 数组。他不再需要那个桶了。

“感觉轻松多了,”Timothy 说。“我不再囤积数据。”

“这就是 Async Generator 的禅意,”Margaret 微笑道。“不要背负未来的重量,只处理眼前的内容。”

0 浏览
Back to Blog

相关文章

阅读更多 »

JavaScript的秘密生活:拒绝

为什么异步错误会绕过 try/catch Timothy 在他的应用程序顶部放置了一个 try/catch 块,确信任何错误都会被捕获:javascript function...