{"id":91,"date":"2020-05-26T15:01:42","date_gmt":"2020-05-26T22:01:42","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=91"},"modified":"2020-06-12T16:18:03","modified_gmt":"2020-06-12T23:18:03","slug":"async-iterators-in-the-azure-sdk-for-javascript-typescript","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/async-iterators-in-the-azure-sdk-for-javascript-typescript\/","title":{"rendered":"Async Iterators in the Azure SDK for JavaScript\/TypeScript"},"content":{"rendered":"<p>A common feature in cloud APIs is paging for list results. Result sets may be massive &#8211; you could have thousands of blobs in a container, for example. Getting all results at once can cause delays in transmission and excessive load on the backend, and might even be so big it won&#8217;t fit into memory in your client. So services offer potentially large collections in pages and developers request one page of results at a time.<\/p>\n<p>The Azure SDK for Javascript and TypeScript abstracts away the details of requesting pages from the service. You write a normal loop, and we take care of the rest. For example, here is the code that iterates through a list of containers in Storage:<\/p>\n<pre><code>const containers = blobServiceClient.listContainers();\nfor await (const container of containers) {\n  console.log(`Container: ${container.name}`);\n}\n<\/code><\/pre>\n<p>How is this done? We use features that were added to recent editions of JavaScript; most notably async iterators. Async Iterators represent a stream of data that is loaded asynchronously. They are used across the Azure SDK to represent asynchronous streams of data such as paginated APIs like above.<\/p>\n<p>Async Iterators, the Async Generators that produce them, and the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/for-await...of\"><code>for-await-of<\/code> loops<\/a> loops that consume them were added in the ES2018 edition of the JavaScript standard. They are supported natively in recent version of modern browsers, but TypeScript can <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/release-notes\/typescript-2-3.html#async-iteration\">compile them down<\/a> to previous versions of JavaScript.<\/p>\n<p>If you&#8217;re already familiar with async functions, promises, generators, and iterators, feel free to skip the background below. If not, that&#8217;s great, most of this blog is for you!<\/p>\n<h2>Background<\/h2>\n<p>At a high level, a function might produce one value or a (possibly unending) sequence of values. It also might do its work synchronously or asynchronously. Considered together, these modes create four possible ways functions might be declared and consumed. Put in a table it looks like the following:<\/p>\n<table>\n<thead>\n<tr>\n<th>\n      <\/th>\n<th>\n        One Value\n      <\/th>\n<th>\n        Many Values\n      <\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\n        <strong>Synchronous<\/strong>\n      <\/td>\n<td>\n        function<br \/>Returns T\n      <\/td>\n<td>\n        generator function<br \/>Returns Iterator of T\n      <\/td>\n<\/tr>\n<tr>\n<td>\n        <strong>Asynchronous<\/strong>\n      <\/td>\n<td>\n        async function<br \/>Returns Promise of T\n      <\/td>\n<td>\n        async generator <br \/>Returns AsyncIterator of T\n      <\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>When JavaScript debuted in 1995, it supported only synchronous functions that produce only a single return value. Developers who wanted to return multiple values, or wanted to produce values asynchronously, had to rely on libraries (for example, node&#8217;s Stream or promises).<\/p>\n<h3>Iterators &amp; Generators<\/h3>\n<p>The 6th edition of the JavaScript language, ES2015, added iterators, iterables, and the <code>for-of<\/code> loop. Iterables are any object with a <code>Symbol.iterator<\/code> method that returns an iterator. Iterators are objects with a <code>next()<\/code> method. Calling <code>next()<\/code> returns an object with <code>value<\/code> and <code>done<\/code> properties which tell you the current iteration value and whether more values are available. The <code>for-of<\/code> loop provides handy syntax for looping over an iterable.<\/p>\n<p>Iterables and iterators aren&#8217;t types but protocols. Any object which has a <code>Symbol.iterator<\/code> method is said to implement the <code>Iterable<\/code> protocol. Likewise, any object with a <code>next<\/code> method is said to implement the <code>Iterator<\/code> protocol.<\/p>\n<p>Let&#8217;s get an understanding of Iterables and Iterators by building them from scratch. First, let&#8217;s make an <code>Iterator<\/code>:<\/p>\n<pre><code>const iterator = {\n  next() {\n    if (this.count &lt;= 2) {\n      return { value: this.count++, done: false };\n    }\n\n    return { value: undefined, done: true };\n  },\n\n  count: 0,\n};\n\niterator.next(); \/\/ { value: 0, done: false }\niterator.next(); \/\/ { value: 1, done: false }\niterator.next(); \/\/ { value: 2, done: false }\niterator.next(); \/\/ { value: undefined, done: true }\n<\/code><\/pre>\n<p>Nothing too fancy here &#8211; we&#8217;ve implemented the <code>Iterator<\/code> protocol because we have a <code>next()<\/code> method which returns the next value in the sequence. Note how the iterator is stateful &#8211; it keeps track of its current position in the iteration. In practice this means you also need a way to vend fresh iterators. We can accomplish this by wrapping the iterator in a function:<\/p>\n<pre><code>function getIterator() {\n  return {\n    next() {\n      if (this.count &lt;= 2) {\n        return { value: this.count++, done: false };\n      }\n\n      return { value: undefined, done: true };\n    },\n\n    count: 0,\n  };\n}\n\nconst iterator1 = getIterator();\niterator1.next(); \/\/ { value: 0, done: false }\n\n\/\/ this iterator is a separate instance with its own internal count\nconst iterator2 = getIterator();\niterator2.next(); \/\/ { value: 0, done: false }\n<\/code><\/pre>\n<p>Now every time I call <code>getIterator()<\/code>, I get a fresh iterator that starts at 0.<\/p>\n<p>We&#8217;ve actually implemented a generator function using regular functions! A generator function creates a function that return an iterator, just like <code>getIterator<\/code> does. When a user calls <code>next()<\/code> on an iterator, the generator function starts running until it hits a <code>yield<\/code> or <code>return<\/code>. If it hits a <code>yield<\/code>, <code>next()<\/code> will return the yielded value with <code>done: false<\/code>, otherwise <code>next()<\/code> will return the returned value with <code>done: true<\/code>. It looks like this:<\/p>\n<pre><code>\/\/ notice the * after function - it makes this a generator function\nfunction* getIterator() {\n  for (let i = 0; i &lt;= 2; i++) {\n    yield i;\n  }\n}\n\nconst iterator1 = getIterator();\niterator1.next(); \/\/ { value: 0, done: false }\n<\/code><\/pre>\n<p>This is pretty handy on its own, but we still need a way to pass around an object that is iterable but isn&#8217;t itself an iterator. An array is an example of this &#8211; you want to pass around the array and let any code iterate over it as needed. This is what the <code>Iterable<\/code> protocol is for &#8211; anything with a <code>Symbol.iterator<\/code> method is iterable. Calling the method returns a fresh iterator.<\/p>\n<p>The following example shows encapsulating <code>getIterator<\/code> above in a <code>Counter<\/code> class. Note that I&#8217;m using the generator syntax, but I could have used the more verbose form we used early on &#8211; there is little difference.<\/p>\n<pre><code>class Counter {\n  constructor(max) {\n    this.max = max;\n  }\n\n  \/\/ the star makes this a generator method\n  *[Symbol.iterator]() {\n    for (let i = 0; i &lt; this.max; i++) {\n      yield i;\n    }\n  }\n}\n\nconst threeCounter = new Counter(3);\nconst iterator1 = threeCounter[Symbol.iterator]();\niterator1.next(); \/\/ { value: 0, done: true }\n<\/code><\/pre>\n<p>Now I know what you&#8217;re thinking: this looks horrible! I have to call some weird <code>Symbol.iterator<\/code> method to get an iterator? Great news: in practice, it is rare to call the Symbol.iterator method yourself. In fact, it is rare to call iterator .next() methods too. Usually, you will use the <code>for-of<\/code> loop:<\/p>\n<pre><code>const threeCounter = new Counter(3);\nfor (let i of threeCounter) {\n  console.log(i);\n}\n\/\/ logs 0, 1, 2\n<\/code><\/pre>\n<p>The <code>for-of<\/code> loop will call the <code>Symbol.iterator<\/code> method on the iterable object for you. It will also call <code>next()<\/code> on the resulting <code>iterator<\/code>, passing each value into the loop, until <code>next()<\/code> returns <code>{ done: true }<\/code>. Some other syntax and built-in libraries will also do this for you, like the spread operator and the Array.of method:<\/p>\n<pre><code>[...threeCounter]; \/\/ [0, 1, 2]\nArray.from(threeCounter); \/\/ [0, 1, 2]\n<\/code><\/pre>\n<p>One more small point: Iterators should also be Iterable. The iterators created from the generator function are iterable, so you don&#8217;t have to do anything to use them with the <code>for-of<\/code> loop. However, If you try to use our early examples where we used the <code>for-of<\/code> loop, you&#8217;ll get an error saying that the iterator isn&#8217;t iterable. This can easily be fixed:<\/p>\n<pre><code>const iterator = {\n  \/\/ add the Symbol.iterator method\n  [Symbol.iterator]() {\n    \/\/ `this` is an iterator, so just return it\n    return this;\n  },\n  next() {\n    if (this.count &lt;= 2) {\n      return { value: this.count++, done: false };\n    }\n\n    return { value: undefined, done: true };\n  },\n\n  count: 0,\n};\n<\/code><\/pre>\n<p>And now you know why TypeScript has three similar-sounding types for iteration: Iterable, Iterator, and IterableIterator. Iterable is an interface with a <code>Symbol.iterator<\/code> method, Iterator is an object with a <code>next()<\/code> method, and IterableIterator has both!<\/p>\n<h3>Promises &amp; Async Functions<\/h3>\n<p>ES2015 added Promises to the language. I won&#8217;t cover the details of Promises here, but <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise\">MDN has a good overview<\/a> complete with handy diagrams. Fundamentally, Promises represent a value that will be produced asynchronously.<\/p>\n<p>The 8th edition of the JavaScript language, ES2017, added <code>async function<\/code>s which offered developers an easy way to define functions that returned Promises.<\/p>\n<p>Inside of an async function, you can <code>await<\/code> any Promise which defers further execution of the function until the awaited Promise resolves successfully. Then you can return your final result and the Promise returned from the async function resolves.<\/p>\n<pre><code>async function getValue() {\n  await delay(100);\n  return \"hi!\";\n}\n\n\/\/ invoke the async function\nconst p = getValue();\n\/\/ it returns a Promise immediately, we don't have the value yet.\n\n\/\/ but after 100ms, it will resolve with \"hi!\", triggering our callback:\np.then((v) =&gt; console.log(v));\n<\/code><\/pre>\n<h2>Async Iterators &amp; Async Generators<\/h2>\n<p>So far, we&#8217;ve gone over three ways to define a function:<\/p>\n<ol>\n<li>The regular <code>function<\/code>, which returns a single value synchronously.<\/li>\n<li>The generator function, <code>function*<\/code>, which returns an iterator for multiple values produced synchronously, and is consumed with the <code>for-of<\/code> loop.<\/li>\n<li>The <code>async function<\/code>, which returns a promise for a value produced asynchronously, and is consumed using <code>await<\/code>.<\/li>\n<\/ol>\n<p>The only remaining part of the puzzle is how do we produce and consume multiple values produced asychronously? Enter the async generators, <code>async function*<\/code>, which return async iterators and are consumed with the <code>for-await-of<\/code> loop!<\/p>\n<p>Async iterators are a mashup of promises and iterators. Like a regular iterator, an async iterator is just an object with a <code>next()<\/code> method, however it returns <em>a promise<\/em> for the iteration result rather than the result itself.<\/p>\n<p>Likewise, async generators are a mashup of async functions and generators &#8211; you can both await asynchronous work and yield values to consumers.<\/p>\n<p>Let&#8217;s write our counter example from above, except where each value is produced after a delay of 100ms:<\/p>\n<pre><code>async function* getAsyncIterator() {\n  for (i = 0; i &lt; 3 i++) {\n    await delay(100);\n    yield i;\n  }\n}\n\nconst iterator = getAsyncIterator();\n\/\/ since iterator.next() returns a promise, we await its value.\nawait iterator.next(); \/\/ { value: 0, done: false }\nawait iterator.next(); \/\/ { value: 1, done: false }\nawait iterator.next(); \/\/ { value: 2, done: false }\nawait iterator.next(); \/\/ { value: undefined, done: true }\n<\/code><\/pre>\n<p>Much like iterators, typically you will not consume the async iterator directly, but use it in conjunction with the <code>for-await-of<\/code> loop which handles all the ceremony for you:<\/p>\n<pre><code>for await (let i of getAsyncIterator()) {\n  console.log(i);\n}\n\n\/\/ logs 0, 1, 2\n<\/code><\/pre>\n<p>As with iterators and generators, the async iterators returned from async generators are also <code>AsyncIterable<\/code>. An <code>AsyncIterable<\/code> is an object with a <code>Symbol.asyncIterable<\/code> method that returns an AsyncIterator. The <code>for-await-of<\/code> loop calls this method to get an object&#8217;s async iterator.<\/p>\n<p>Hence, the three TypeScript types for async iteration: <code>AsyncIterator<\/code>, <code>AsyncIterable<\/code>, and <code>AsyncIterableIterator<\/code>. An AsyncIterator has a <code>next()<\/code> method that returns a promise for an iteration result, an <code>AsyncIterable<\/code> has a <code>Symbol.asyncIterable<\/code> method that returns an <code>AsyncIterator<\/code>, and an <code>AsyncIterableIterator<\/code> has both!<\/p>\n<h2>Async Iterators in the Azure SDK for JavaScript &amp; TypeScript<\/h2>\n<p>Our new SDKs use async iterators whenever there is a large collection a developer wants to iterate over. A common example is paginated APIs. Let&#8217;s take an example:<\/p>\n<pre><code>const containers = blobServiceClient.listContainers();\nfor await (const container of containers) {\n  console.log(`Container: ${container.name}`);\n}\n<\/code><\/pre>\n<p><code>containers<\/code> is what we call a <code>PagedAsyncIterableIterator<\/code>. It&#8217;s an async iterator with an additional method, <code>byPage()<\/code>, that exposes an async iterator for the underlying pages. Sometimes pages are more convenient to work with:<\/p>\n<pre><code>const containerPages = blobServiceClient.listContainers().byPage();\n\/\/ loop over each page\nfor await (const page of containerPages) {\n  \/\/ loop over each item in the page\n  for (const container of page) {\n    console.log(`Container: ${container.name}`);\n  }\n}\n<\/code><\/pre>\n<p>The three major advantages of using async iterators over manual pagination or APIs that return all items in an array are that:<\/p>\n<ol>\n<li>You can consume asynchronous sequences of values using a fairly standard loop syntax. The complexity of dealing with paginated APIs is completely encapsulated behind the Async Iterator interface.<\/li>\n<li>You pull new items from the service on-demand as needed. If for whatever reason you don&#8217;t need to iterate any longer, just <code>break<\/code> like any old loop and you won&#8217;t fetch any more data.<\/li>\n<li>We&#8217;re set up for a future where async iterators, like iterators, have deep integration in the language and great support across the ecosystem.<\/li>\n<\/ol>\n<p>Let&#8217;s dive a bit deeper into each of these.<\/p>\n<h4>Standard loop syntax<\/h4>\n<p>The <code>for-await-of<\/code> loop makes consuming async iterators easy. No messy code dealing with promises and plumbing continuation tokens.<\/p>\n<h4>Pull items on demand<\/h4>\n<p>When using iterating an async iterator, you&#8217;re pulling data as you need it, not all in advance. That means you don&#8217;t need to fetch a potentially huge list and store it in memory. It also means you don&#8217;t fetch more data than you need. To understand how this works, let&#8217;s walk through the example above.<\/p>\n<p>First, we call <code>listContainers()<\/code>, which returns an async iterator. At this point, the service hasn&#8217;t even been called.<\/p>\n<p>On the next line, we start the <code>for-await-of<\/code> loop. JavaScript calls <code>.next()<\/code> on the iterator and awaits the result. Our library code will fetch the next page if needed, pull out the next container in the page, and yield it back, kicking off the loop body. Once the loop body is finished executing, the process repeats.<\/p>\n<p>If at any point you break out of the <code>for-await-of<\/code> loop, or an error is thrown, then no more data is requested from the service.<\/p>\n<h4>Language &amp; library integration<\/h4>\n<p>Async iterators are a fairly recent addition to the language and thus far don&#8217;t have much support other than the <code>for-await-of<\/code> loop. Thankfully this is a major win and more than enough to justify using async iterators today. However, the future will likely bring further support for async iterators such as methods for applying array-like operators like <code>map<\/code>, <code>filter<\/code>, and friends.<\/p>\n<p>But more exciting is that Async Iterators are a standard feature and so libraries have stepped in to fill the gaps.<\/p>\n<p>For example, sometimes it is really convenient to get all of your items into an array. Generally we don&#8217;t offer a simple API in our libraries to do this because there&#8217;s a good chance you&#8217;ll pull down huge amounts of data you don&#8217;t need and end up with a hefty bill. That said, sometimes you know you&#8217;re dealing with a small collection and just want to do array things on it. A library like <code>ix<\/code> provides a function to do just this:<\/p>\n<pre><code>import { toArray } from \"ixjs\/asynciterable\";\nlet items = await toArray(client.listThings());\n\/\/ now items is a regular array of items!\n<\/code><\/pre>\n<p>You&#8217;ll find other libraries on npm for doing all sorts of things with async iterators, and in the future this support will only grow. Adopting async iterators in the Azure SDK makes sure we&#8217;ll interoperate seamlessly with great libraries across our ecosystem.<\/p>\n<h2>Further reading<\/h2>\n<ul>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Statements\/for-await...of\">MDN documentation for the <code>for-await-of<\/code> loop<\/a>.<\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Symbol\/asyncIterator\">MDN documentation for <code>Symbol.asyncIterator<\/code><\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Guide\/Iterators_and_Generators\">MDN documentation for iterators and generators<\/a><\/li>\n<li><a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/release-notes\/typescript-2-3.html#async-iteration\">TypeScript 2.3 Release Notes<\/a> which added support for async iteration<\/li>\n<li><a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/iterators-and-generators.html\">TypeScript handbook on iterators and generators<\/a><\/li>\n<\/ul>\n<h2>Want to hear more?<\/h2>\n<p>Follow us on Twitter at <a href=\"https:\/\/twitter.com\/AzureSDK\">@AzureSDK<\/a>. We&#8217;ll be covering more best practices in cloud-native development as well as providing updates on our progress in developing the next generation of Azure SDKs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A common feature in cloud APIs is paging for list results. Result sets may be massive &#8211; you could have thousands of blobs in a container, for example. Getting all results at once can cause delays in transmission and excessive load on the backend.  We&#8217;ll show you how the Azure SDK handles this issue.<\/p>\n","protected":false},"author":31967,"featured_media":97,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[159],"class_list":["post-91","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-javascript"],"acf":[],"blog_post_summary":"<p>A common feature in cloud APIs is paging for list results. Result sets may be massive &#8211; you could have thousands of blobs in a container, for example. Getting all results at once can cause delays in transmission and excessive load on the backend.  We&#8217;ll show you how the Azure SDK handles this issue.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/91","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/31967"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=91"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/91\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/97"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=91"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=91"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=91"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}