title: Asking for examples of async generators not directly transformable into manually implemented async iteration
body: <p>Async generators use an <a href="https://exploringjs.com/es2018-es2019/ch_asynchronous-iteration.html#async-generators" rel="nofollow noreferrer">internal queue</a> to handle synchronous <strong>next</strong>, <strong>thrown</strong>, and <strong>return</strong> methods calls.</p>
  
  <p>I was trying to construct a situation where this queue is mandatory for the success of the iteration itself. Therefore, I'm looking for some cases where a manual implementation of the async iteration interfaces, without a custom reimplementation of the queue, is not enough.</p>
  
  <p>The following is an example but not so good, because the general time consistency is not maintained but the iteration result is correct at each step:</p>
  
  <pre><code>function aItsFactory() {
      let i = 1;
      return {
          async next() {
              if(i &gt; 5) return Promise.resolve({ value: void 0, done: true });
              const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${i++}`).then(x =&gt; x.json());
              return Promise.resolve({ value: res, done: false });
          },
          [Symbol.asyncIterator]() { 
              return this;
          }
      }
  }
  
  const ait = aItsFactory();
  
  
  // general time consistency is lost, because e.g. the fourth call
  // is started with the previous three and it could end before the others.
  
  // But the 'i' state is correctly shared so the fifth call
  // is correctly requesting the element number five to the source
  // and the last call will correctly receive { done: true }
  
  ;(async () =&gt; {
        ait.next();
        ait.next();
        ait.next();
        ait.next();
        console.log(await ait.next()); // { done: false, value: { userId: 1, id: 5, title: ... } }
  
        console.log(await ait.next()); // { done: true, value: undefined }
  })();
  </code></pre>
  
  <p>It could be argued that without a proper queue the iteration concept itself will be lost. That is because of the <strong>active</strong> parallel <strong>next</strong> calls.</p>
  
  <p>Anyway, <strong>I'd like to find some examples, also trivial ones, which make clear that async generators are a better approach for creating well-formed async iterables than a manual implementation of the async iteration interfaces</strong>.</p>
  
  <p><strong>------ Edit ------</strong></p>
  
  <p>Let's talk about an improved situation:</p>
  
  <pre><code>function aItsFactory() {
      let i = 1;
      let done = false;
  
      return {
          async next() {
  
              if (done) return Promise.resolve({
                  done: true,
                  value: undefined
              });
  
              const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${i++}`).then(x =&gt; x.json());
  
              if (Object.keys(res).length === 0) { // the jsonplaceholder source is out of bounds
                  done = true;
                  return Promise.resolve({
                      done: true,
                      value: undefined
                  });
              } else {
                  return Promise.resolve({
                      done: false,
                      value: res
                  });
              };
  
          },
          [Symbol.asyncIterator]() {
              return this;
          }
      }
  }
  
  const ait = aItsFactory();
  
  // now lot of sync call to 'ait.next'
  </code></pre>
  
  <p>Here the <code>done</code> resolution is fully asynchronous.
  From an async iteration perspective, the code is wrong because each <code>next</code> call should be forced to <code>await</code> the outcome of the previous to know if it was the last valid iteration. In such a case, the current <code>next</code> should do nothing, immediately returning <code>Promise.resolve({done:true, value:undefined})</code>.
  This is only possible thanks to a queue of sync <code>next</code> calls.</p>
  
  <p>But in practice the major risk of going out-of-bounds, calling <code>ait.next()</code> repeatedly, are some useless AJAX request.
  Don't misunderstand me, I'm not saying that we can turn a blind eye.
  The point is that each step of the async iteration itself will never be broken.</p>
  
  <p>I'd like to see a situation, not too unrealistic, where the iteration itself could be compromised at each step if all the <strong>next</strong> calls are not enqueued. </p>