[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"article-array-from-async-async-iterable":32,"code:js:true:q66ko3":248,"code:js:true:1mwqtf9":249,"code:js:true:e8njmh":250,"code:js:true:1b6us1m":251,"code:js:true:iheriu":252,"code:js:true:od2zmo":253,"code:js:true:1246pa9":254,"code:js:true:15kl7aw":255},[4,20],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Build. Learn. Ship.","Practical courses, engineering-grade articles and open-source tools for people who ship.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Structured paths, listening drills and spaced repetition that actually sticks.","amber-400","⌘",[13,15,29],"es",{"courses":17,"paths":17,"articles":18,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":17},2,{"id":33,"slug":34,"title":35,"subtitle":36,"excerpt":37,"coverUrl":38,"locale":13,"readingMinutes":39,"publishedAt":40,"viewCount":41,"likeCount":19,"commentCount":19,"author":42,"vertical":47,"topic":48,"tags":51,"_count":63,"playground":65,"body":67,"bodyMd":230,"seo":231,"translationGroupId":235,"thread":236,"assessments":238,"translations":244,"quiz":246},"019fe660-de51-759d-935f-dbda9e7e38b5","array-from-async-async-iterable","You're collecting async iterable results with a for-await loop. `Array.fromAsync` does it in one call.",null,"A for-await loop that pushes into an array, or the `await Promise.all([...asyncIterable])` workaround that silently fails — `Array.fromAsync` replaces both with a single awaited call. It's Baseline 2024.","\u002Fmedia\u002Fcovers\u002Farray-from-async-async-iterable.png",4,"2026-08-05T08:42:50.920Z",179,{"id":43,"name":44,"username":45,"avatarUrl":36,"headline":46},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":49,"name":50},"javascript","JavaScript",[52,54,57,60],{"slug":49,"name":53,"color":36},"Javascript",{"slug":55,"name":56,"color":36},"webdev","Webdev",{"slug":58,"name":59,"color":36},"frontend","Frontend",{"slug":61,"name":62,"color":36},"async","Async",{"assessments":64},1,{"slug":34,"title":66},"Array.fromAsync — interactive playground",{"blocks":68,"version":64},[69,73,79,82,87,90,94,97,101,105,108,111,115,118,121,124,127,131,134,138,141,144,147,150,154,157,160,163,166,170,173,176,179,182,185,188,191,194,197,200,203,206,209,212,215,218,221],{"id":70,"html":71,"type":72},"b1","\u003Cp>When you have an async iterable — a \u003Ccode>ReadableStream\u003C\u002Fcode>, a generator that fetches paginated results, a database cursor — and you need its values in a plain array, you reach for a loop.\u003C\u002Fp>","paragraph",{"id":74,"code":75,"type":76,"language":77,"highlight":78},"b2","const results = [];\nfor await (const item of asyncSource) {\n  results.push(item);\n}","code","js",[],{"id":80,"html":81,"type":72},"b3","\u003Cp>That works. But it&#39;s four lines of ceremony for &quot;give me an array of everything this produces.&quot; \u003Ccode>Array.fromAsync\u003C\u002Fcode> is the one-liner that&#39;s been missing.\u003C\u002Fp>",{"id":83,"html":84,"text":85,"type":86,"level":31},"b4","The spread workaround doesn&#39;t work","The spread workaround doesn't work","heading",{"id":88,"html":89,"type":72},"b5","\u003Cp>If you&#39;ve tried \u003Ccode>[...asyncIterable]\u003C\u002Fcode>, you know it throws. Spread syntax works with synchronous iterables only. The \u003Ccode>await Promise.all([...asyncIterable])\u003C\u002Fcode> trick fails too — the spread happens before \u003Ccode>await\u003C\u002Fcode>, which means JavaScript tries to spread a synchronous iterator that doesn&#39;t exist on the async source.\u003C\u002Fp>",{"id":91,"code":92,"type":76,"language":77,"highlight":93},"b6","\u002F\u002F ❌ TypeError: asyncSource is not iterable\nconst results = [...asyncSource];\n\n\u002F\u002F ❌ Also fails — spread is sync, runs before await\nconst results = await Promise.all([...asyncSource]);",[],{"id":95,"html":96,"type":72},"b7","\u003Cp>The for-await loop is the correct fallback. But it&#39;s exactly the kind of boilerplate a standard library should absorb.\u003C\u002Fp>",{"id":98,"html":99,"text":100,"type":86,"level":31},"b8","\u003Ccode>Array.fromAsync\u003C\u002Fcode> in one call","Array.fromAsync in one call",{"id":102,"code":103,"type":76,"language":77,"highlight":104},"b9","const results = await Array.fromAsync(asyncSource);",[],{"id":106,"html":107,"type":72},"b10","\u003Cp>That&#39;s it. It pulls one value from the source, awaits it, stores it, then pulls the next — returning a fully-populated plain array when the source is exhausted.\u003C\u002Fp>",{"id":109,"html":110,"type":72},"b11","\u003Cp>Like \u003Ccode>Array.from()\u003C\u002Fcode>, it accepts a mapping function as the second argument:\u003C\u002Fp>",{"id":112,"code":113,"type":76,"language":77,"highlight":114},"b12","const doubled = await Array.fromAsync(asyncNumbers, n => n * 2);",[],{"id":116,"html":117,"type":72},"b13","\u003Cp>The mapper runs after each value has been awaited. You can return a promise from the mapper too — \u003Ccode>Array.fromAsync\u003C\u002Fcode> awaits that as well before moving on.\u003C\u002Fp>",{"id":119,"html":120,"text":120,"type":86,"level":31},"b14","What sources it accepts",{"id":122,"html":123,"type":72},"b15","\u003Cp>\u003Ccode>Array.fromAsync\u003C\u002Fcode> accepts three kinds of input:\u003C\u002Fp>",{"id":125,"html":126,"type":72},"b16","\u003Cp>\u003Cstrong>Async iterables\u003C\u002Fstrong> — anything with a \u003Ccode>[Symbol.asyncIterator]()\u003C\u002Fcode> method. This is the main use case: generators, streams, cursors, any API that produces values lazily over time.\u003C\u002Fp>",{"id":128,"code":129,"type":76,"language":77,"highlight":130},"b17","async function* paginate(cursor) {\n  while (cursor.hasMore) {\n    const page = await cursor.fetch();\n    yield* page.items;\n    cursor.advance();\n  }\n}\n\nconst allItems = await Array.fromAsync(paginate(cursor));",[],{"id":132,"html":133,"type":72},"b18","\u003Cp>\u003Cstrong>Sync iterables\u003C\u002Fstrong> with an async mapper — this replaces the common \u003Ccode>await Promise.all(array.map(async fn))\u003C\u002Fcode> pattern, with one key difference explained below.\u003C\u002Fp>",{"id":135,"code":136,"type":76,"language":77,"highlight":137},"b19","const users = await Array.fromAsync([1, 2, 3], async id => {\n  const res = await fetch(`\u002Fapi\u002Fusers\u002F${id}`);\n  return res.json();\n});",[],{"id":139,"html":140,"type":72},"b20","\u003Cp>\u003Cstrong>Array-like objects\u003C\u002Fstrong> — objects with numeric indices and a \u003Ccode>length\u003C\u002Fcode> property, same as \u003Ccode>Array.from\u003C\u002Fcode>.\u003C\u002Fp>",{"id":142,"html":143,"text":143,"type":86,"level":31},"b21","Sequential, not concurrent",{"id":145,"html":146,"type":72},"b22","\u003Cp>This is the most important thing to understand about \u003Ccode>Array.fromAsync\u003C\u002Fcode>: it processes values one at a time, in order. It awaits each value fully before pulling the next.\u003C\u002Fp>",{"id":148,"html":149,"type":72},"b23","\u003Cp>This is different from \u003Ccode>Promise.all\u003C\u002Fcode>, which fires all promises concurrently and waits for all of them together.\u003C\u002Fp>",{"id":151,"code":152,"type":76,"language":77,"highlight":153},"b24","\u002F\u002F ✅ Use Promise.all when you want all fetches to run in parallel\nconst [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);\n\n\u002F\u002F ✅ Use Array.fromAsync when the source is lazy — values produced one at a time\nconst results = await Array.fromAsync(asyncGenerator());",[],{"id":155,"html":156,"type":72},"b25","\u003Cp>When you pass a sync array with an async mapper, \u003Ccode>Array.fromAsync\u003C\u002Fcode> fetches item 1, awaits the result, stores it, then fetches item 2. There&#39;s no parallelism inside the pipeline. If you&#39;re mapping over a known array and want concurrent fetches, \u003Ccode>Promise.all\u003C\u002Fcode> is still the right tool.\u003C\u002Fp>",{"id":158,"html":159,"type":72},"b26","\u003Cp>The sequential behavior is intentional for lazy sources: a generator or stream doesn&#39;t know what to produce next until you ask — you can&#39;t fan out requests that haven&#39;t been decided yet.\u003C\u002Fp>",{"id":161,"html":162,"text":162,"type":86,"level":31},"b27","A practical pattern: async generator pipeline",{"id":164,"html":165,"type":72},"b28","\u003Cp>Async generators are where \u003Ccode>Array.fromAsync\u003C\u002Fcode> earns its place. Consider a paginated API client:\u003C\u002Fp>",{"id":167,"code":168,"type":76,"language":77,"highlight":169},"b29","async function* fetchPages(url) {\n  let next = url;\n  while (next) {\n    const res = await fetch(next);\n    const data = await res.json();\n    yield* data.items;\n    next = data.nextPage ?? null;\n  }\n}\n\n\u002F\u002F Before: manual loop\nconst all = [];\nfor await (const item of fetchPages('\u002Fapi\u002Fitems')) {\n  all.push(item);\n}\n\n\u002F\u002F After: one call\nconst all = await Array.fromAsync(fetchPages('\u002Fapi\u002Fitems'));",[],{"id":171,"html":172,"type":72},"b30","\u003Cp>Same result. The generator drives pagination and \u003Ccode>Array.fromAsync\u003C\u002Fcode> collects everything, stopping when the generator returns.\u003C\u002Fp>",{"id":174,"html":175,"text":175,"type":86,"level":31},"b31","Browser support",{"id":177,"html":178,"type":72},"b32","\u003Cp>\u003Ccode>Array.fromAsync\u003C\u002Fcode> is \u003Cstrong>Baseline 2024\u003C\u002Fstrong>: Chrome 121 (January 2024), Firefox 119 (October 2023), Safari 17.4 (March 2024), Node.js 22. For older targets, \u003Ccode>core-js\u003C\u002Fcode> 3.38+ includes a polyfill, and the manual for-await loop is always a valid fallback.\u003C\u002Fp>",{"id":180,"html":181,"type":72},"b33","\u003C!-- playground:start -->",{"id":183,"html":184,"text":184,"type":86,"level":31},"b34","🎮 Try it yourself",{"id":186,"html":187,"type":72},"b35","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fposts\u002F2026-08-05-array-from-async-async-iterable\u002Fplayground\u002F\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":189,"html":190,"type":72},"b36","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":192,"html":193,"type":72},"b37","\u003C!-- playground:end -->",{"id":195,"html":196,"type":72},"b38","\u003C!-- quiz:start -->",{"id":198,"html":199,"text":199,"type":86,"level":31},"b39","🧠 Test yourself",{"id":201,"html":202,"type":72},"b40","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fquiz\u002Ftake.html?post=2026-08-05-array-from-async-async-iterable\">Take the 8-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":204,"html":205,"type":72},"b41","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":207,"html":208,"type":72},"b42","\u003C!-- quiz:end -->",{"id":210,"html":211,"text":211,"type":86,"level":31},"b43","The takeaway",{"id":213,"html":214,"type":72},"b44","\u003Cp>Search your codebase for \u003Ccode>for await ... push\u003C\u002Fcode> patterns that end with the array being returned or used. Each one is a direct candidate for \u003Ccode>await Array.fromAsync(source)\u003C\u002Fcode>. When you&#39;re mapping an async function over a sync array and want sequential execution, \u003Ccode>Array.fromAsync(array, asyncMapper)\u003C\u002Fcode> replaces the manual loop. When you want concurrent execution over a known array, stick with \u003Ccode>await Promise.all(array.map(asyncMapper))\u003C\u002Fcode>. The distinction is sequential vs parallel — know which you need before reaching for either.\u003C\u002Fp>",{"id":216,"type":217},"b45","divider",{"id":219,"html":220,"type":72},"b46","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":222,"type":223,"items":224,"ordered":18},"b47","list",[225,226,227,228,229],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","💼 \u003Cstrong>LinkedIn\u003C\u002Fstrong> — \u003Ca href=\"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F\">linkedin.com\u002Fin\u002Fparsa-jiravand\u003C\u002Fa>","✉️ \u003Cstrong>Email\u003C\u002Fstrong> (work &amp; contract inquiries): \u003Ca href=\"mailto:bestpractice2026@gmail.com\">bestpractice2026@gmail.com\u003C\u002Fa>","When you have an async iterable — a `ReadableStream`, a generator that fetches paginated results, a database cursor — and you need its values in a plain array, you reach for a loop.\n\n```js\nconst results = [];\nfor await (const item of asyncSource) {\n  results.push(item);\n}\n```\n\nThat works. But it's four lines of ceremony for \"give me an array of everything this produces.\" `Array.fromAsync` is the one-liner that's been missing.\n\n## The spread workaround doesn't work\n\nIf you've tried `[...asyncIterable]`, you know it throws. Spread syntax works with synchronous iterables only. The `await Promise.all([...asyncIterable])` trick fails too — the spread happens before `await`, which means JavaScript tries to spread a synchronous iterator that doesn't exist on the async source.\n\n```js\n\u002F\u002F ❌ TypeError: asyncSource is not iterable\nconst results = [...asyncSource];\n\n\u002F\u002F ❌ Also fails — spread is sync, runs before await\nconst results = await Promise.all([...asyncSource]);\n```\n\nThe for-await loop is the correct fallback. But it's exactly the kind of boilerplate a standard library should absorb.\n\n## `Array.fromAsync` in one call\n\n```js\nconst results = await Array.fromAsync(asyncSource);\n```\n\nThat's it. It pulls one value from the source, awaits it, stores it, then pulls the next — returning a fully-populated plain array when the source is exhausted.\n\nLike `Array.from()`, it accepts a mapping function as the second argument:\n\n```js\nconst doubled = await Array.fromAsync(asyncNumbers, n => n * 2);\n```\n\nThe mapper runs after each value has been awaited. You can return a promise from the mapper too — `Array.fromAsync` awaits that as well before moving on.\n\n## What sources it accepts\n\n`Array.fromAsync` accepts three kinds of input:\n\n**Async iterables** — anything with a `[Symbol.asyncIterator]()` method. This is the main use case: generators, streams, cursors, any API that produces values lazily over time.\n\n```js\nasync function* paginate(cursor) {\n  while (cursor.hasMore) {\n    const page = await cursor.fetch();\n    yield* page.items;\n    cursor.advance();\n  }\n}\n\nconst allItems = await Array.fromAsync(paginate(cursor));\n```\n\n**Sync iterables** with an async mapper — this replaces the common `await Promise.all(array.map(async fn))` pattern, with one key difference explained below.\n\n```js\nconst users = await Array.fromAsync([1, 2, 3], async id => {\n  const res = await fetch(`\u002Fapi\u002Fusers\u002F${id}`);\n  return res.json();\n});\n```\n\n**Array-like objects** — objects with numeric indices and a `length` property, same as `Array.from`.\n\n## Sequential, not concurrent\n\nThis is the most important thing to understand about `Array.fromAsync`: it processes values one at a time, in order. It awaits each value fully before pulling the next.\n\nThis is different from `Promise.all`, which fires all promises concurrently and waits for all of them together.\n\n```js\n\u002F\u002F ✅ Use Promise.all when you want all fetches to run in parallel\nconst [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);\n\n\u002F\u002F ✅ Use Array.fromAsync when the source is lazy — values produced one at a time\nconst results = await Array.fromAsync(asyncGenerator());\n```\n\nWhen you pass a sync array with an async mapper, `Array.fromAsync` fetches item 1, awaits the result, stores it, then fetches item 2. There's no parallelism inside the pipeline. If you're mapping over a known array and want concurrent fetches, `Promise.all` is still the right tool.\n\nThe sequential behavior is intentional for lazy sources: a generator or stream doesn't know what to produce next until you ask — you can't fan out requests that haven't been decided yet.\n\n## A practical pattern: async generator pipeline\n\nAsync generators are where `Array.fromAsync` earns its place. Consider a paginated API client:\n\n```js\nasync function* fetchPages(url) {\n  let next = url;\n  while (next) {\n    const res = await fetch(next);\n    const data = await res.json();\n    yield* data.items;\n    next = data.nextPage ?? null;\n  }\n}\n\n\u002F\u002F Before: manual loop\nconst all = [];\nfor await (const item of fetchPages('\u002Fapi\u002Fitems')) {\n  all.push(item);\n}\n\n\u002F\u002F After: one call\nconst all = await Array.fromAsync(fetchPages('\u002Fapi\u002Fitems'));\n```\n\nSame result. The generator drives pagination and `Array.fromAsync` collects everything, stopping when the generator returns.\n\n## Browser support\n\n`Array.fromAsync` is **Baseline 2024**: Chrome 121 (January 2024), Firefox 119 (October 2023), Safari 17.4 (March 2024), Node.js 22. For older targets, `core-js` 3.38+ includes a polyfill, and the manual for-await loop is always a valid fallback.\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fposts\u002F2026-08-05-array-from-async-async-iterable\u002Fplayground\u002F)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 8-question quiz →](https:\u002F\u002Fdaily-post-dev.netlify.app\u002Fquiz\u002Ftake.html?post=2026-08-05-array-from-async-async-iterable)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n\n## The takeaway\n\nSearch your codebase for `for await ... push` patterns that end with the array being returned or used. Each one is a direct candidate for `await Array.fromAsync(source)`. When you're mapping an async function over a sync array and want sequential execution, `Array.fromAsync(array, asyncMapper)` replaces the manual loop. When you want concurrent execution over a known array, stick with `await Promise.all(array.map(asyncMapper))`. The distinction is sequential vs parallel — know which you need before reaching for either.\n\n---\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)\n- 💼 **LinkedIn** — [linkedin.com\u002Fin\u002Fparsa-jiravand](https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F)\n- ✉️ **Email** (work & contract inquiries): [bestpractice2026@gmail.com](mailto:bestpractice2026@gmail.com)",{"title":232,"canonical":233,"description":234},"You're collecting async iterable results with a for-await loop. `Array","https:\u002F\u002Fbestpractic.org\u002Fblog\u002Farray-from-async-async-iterable","A for-await loop that pushes into an array, or the `await Promise.all([...asyncIterable])` workaround that silently fails — `Array.fromAsync` replaces both with a single awaited ca","019fe660-de51-759d-935f-dfe3f9c67b01",{"id":237,"locked":18},"019fe660-e549-71a3-9c93-1eb02c238b81",[239],{"id":240,"slug":34,"title":241,"_count":242},"019fe776-ba13-721a-9b41-ecc76a7d836e","Array.fromAsync — async iterables into arrays",{"questions":243},8,[245],{"locale":13,"slug":34},{"id":240,"slug":34,"title":241,"_count":247,"questionCount":243},{"questions":243},"\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> results \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>;\n\u003Cspan class=\"shj-kwd\">for\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> item \u003Cspan class=\"shj-kwd\">of\u003C\u002Fspan> asyncSource\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  results\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">push\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>item\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F ❌ TypeError: asyncSource is not iterable\n\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> results \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">...\u003C\u002Fspan>asyncSource\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>;\n\n\u003Cspan class=\"shj-cmnt\">\u002F\u002F ❌ Also fails — spread is sync, runs before await\n\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> results \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Promise\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">all\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">...\u003C\u002Fspan>asyncSource\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-oneline\" data-lang=\"js\">\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> results \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Array\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fromAsync\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>asyncSource\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-oneline\" data-lang=\"js\">\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> doubled \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Array\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fromAsync\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>asyncNumbers\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> n \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> n \u003Cspan class=\"shj-oper\">*\u003C\u002Fspan> \u003Cspan class=\"shj-num\">2\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003Cdiv>9\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">async\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">function\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">*\u003C\u002Fspan> \u003Cspan class=\"shj-func\">paginate\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>cursor\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">while\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>cursor\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>hasMore\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n    \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> page \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> cursor\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fetch\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n    \u003Cspan class=\"shj-kwd\">yield\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">*\u003C\u002Fspan> page\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>items;\n    cursor\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">advance\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> allItems \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Array\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fromAsync\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-func\">paginate\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>cursor\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> users \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Array\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fromAsync\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-num\">1\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-num\">2\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-num\">3\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">async\u003C\u002Fspan> id \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> res \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-func\">fetch\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">`\u002Fapi\u002Fusers\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">${\u003C\u002Fspan>id\u003Cspan class=\"shj-kwd\">}\u003C\u002Fspan>\u003Cspan class=\"shj-str\">`\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-kwd\">return\u003C\u002Fspan> res\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">json\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F ✅ Use Promise.all when you want all fetches to run in parallel\n\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>a\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> b\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> c\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan> \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Promise\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">all\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fetchA\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-func\">fetchB\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-func\">fetchC\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\n\u003Cspan class=\"shj-cmnt\">\u002F\u002F ✅ Use Array.fromAsync when the source is lazy — values produced one at a time\n\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> results \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Array\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fromAsync\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-func\">asyncGenerator\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003Cdiv>9\u003C\u002Fdiv>\u003Cdiv>10\u003C\u002Fdiv>\u003Cdiv>11\u003C\u002Fdiv>\u003Cdiv>12\u003C\u002Fdiv>\u003Cdiv>13\u003C\u002Fdiv>\u003Cdiv>14\u003C\u002Fdiv>\u003Cdiv>15\u003C\u002Fdiv>\u003Cdiv>16\u003C\u002Fdiv>\u003Cdiv>17\u003C\u002Fdiv>\u003Cdiv>18\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">async\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">function\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">*\u003C\u002Fspan> \u003Cspan class=\"shj-func\">fetchPages\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>url\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">let\u003C\u002Fspan> next \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> url;\n  \u003Cspan class=\"shj-kwd\">while\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>next\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n    \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> res \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-func\">fetch\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>next\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n    \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> data \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> res\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">json\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n    \u003Cspan class=\"shj-kwd\">yield\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">*\u003C\u002Fspan> data\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>items;\n    next \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> data\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>nextPage \u003Cspan class=\"shj-oper\">??\u003C\u002Fspan> \u003Cspan class=\"shj-num\">null\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-cmnt\">\u002F\u002F Before: manual loop\n\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> all \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>;\n\u003Cspan class=\"shj-kwd\">for\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> item \u003Cspan class=\"shj-kwd\">of\u003C\u002Fspan> \u003Cspan class=\"shj-func\">fetchPages\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'\u002Fapi\u002Fitems'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  all\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">push\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>item\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-cmnt\">\u002F\u002F After: one call\n\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> all \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">await\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Array\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fromAsync\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-func\">fetchPages\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'\u002Fapi\u002Fitems'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>"]