Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document “AsyncGenerator” & “AsyncGeneratorFunction” #2861

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6de1a35
Document “AsyncGenerator” & “AsyncGeneratorFunction”
DerekNonGeneric Mar 4, 2021
a8d56b1
fixup: use one <code> per argument in param definition
DerekNonGeneric Mar 4, 2021
ef06d6e
fixup: pair `.notecard` w/ `.note`s
DerekNonGeneric Mar 4, 2021
c1a2f09
fixup: format Note sections w/ headings
DerekNonGeneric Mar 4, 2021
cff7b5d
fixup: `JSxRef` -> `jsxref`
DerekNonGeneric Mar 4, 2021
d38696c
fixup: improve description for AsyncGenerator.prototype.throw()
DerekNonGeneric Mar 5, 2021
77c1e75
fixup: improve naming & var -> const in constructor example
DerekNonGeneric Mar 5, 2021
15a51eb
fixup: improve See_also for AsynGeneratorFunction
DerekNonGeneric Mar 5, 2021
658a2b4
fixup: improve See_also for AsynGenerator
DerekNonGeneric Mar 5, 2021
ccfa77d
fixup: use multiline syntax notation instead of square bracket notation
DerekNonGeneric Mar 5, 2021
dddfb8a
async review
Rumyra Mar 9, 2021
ee4aca0
fixup: modify AsyncGeneratorFunction example to work w/o TLA
DerekNonGeneric Mar 12, 2021
033ba8f
add AsyncGenerator methods & update code sample variable names
DerekNonGeneric Mar 13, 2021
1ab12a5
statement operator
Rumyra Mar 23, 2021
76a0bb5
working on statement
Rumyra Mar 24, 2021
d58fe42
Update files/en-us/web/javascript/reference/operators/async_function_…
Rumyra Mar 25, 2021
c331788
rel notes
Rumyra Jul 14, 2021
c6f5f6e
Merge branch 'main' into feat/add-missing-ctrl-abstr-pages
Rumyra Jul 14, 2021
cf479a0
tidying up async gen docs
Rumyra Jul 14, 2021
0c8af2e
Revert "rel notes"
Rumyra Jul 14, 2021
0d1ab7a
Update files/en-us/web/javascript/reference/global_objects/asyncgener…
Rumyra Aug 3, 2021
f0be1e2
Update files/en-us/web/javascript/reference/global_objects/asyncgener…
Rumyra Aug 3, 2021
0786efa
working on it
Rumyra Aug 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
title: AsyncGenerator
slug: Web/JavaScript/Reference/Global_Objects/AsyncGenerator
tags:
- Class
- ECMAScript 2018
- Generator
- JavaScript
- Async Generator
- Async Iterator
- Reference
browser-compat: javascript.builtins.AsyncGenerator
---
<div>{{JSRef}}</div>

<p>The <code><strong>AsyncGenerator</strong></code> object is returned by an {{jsxref("Statements/async_function*", "async generator function", "", 1)}} and it conforms to both the <a href="/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol">iterable protocol</a> and the <a href="/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol">iterator protocol</a>.</p>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading the specification some more, I noticed that we may have made a copying error here when saying that it “conforms to both the iterable protocol and iterator protocol”, since it seems to actually conform to the async iterable protocol and async iterator protocol

Refs: https://tc39.es/ecma262/#sec-asyncgenerator-objects

We should ensure that this is corrected in the PR that adds this page.

Unfortunately, it seems like MDN is missing pages for those protocols (previous links make no mention)…

/cc @Rumyra


<p>Async generators always yield a {{jsxref("Promise")}} object.</p>

<h2 id="Constructor">Constructor</h2>

<p>This object cannot be instantiated directly. Instead, an <code>AsyncGenerator</code> instance can be returned from an {{jsxref("Statements/async_function*", "async generator function", "", "1")}}.</p>


<pre class="brush: js">async function* createAsyncGenerator() {
DerekNonGeneric marked this conversation as resolved.
Show resolved Hide resolved
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}

const asyncGen = createAsyncGenerator();

asyncGen.next()
.then(res => console.log(res.value)); // 1
asyncGen.next()
.then(res => console.log(res.value)); // 2
asyncGen.next()
.then(res => console.log(res.value)); // 3</pre>

<h2 id="Instance_methods">Instance methods</h2>

<dl>
<dt>{{jsxref("AsyncGenerator.prototype.next()")}}</dt>
<dd>Returns a {{jsxref("Promise")}} which will be resolved with the given value yielded by the {{jsxref("Operators/yield", "yield")}} expression.</dd>
<dt>{{jsxref("AsyncGenerator.prototype.return()")}}</dt>
<dd>Returns a {{jsxref("Promise")}} which will be resolved with the given value yielded by the {{jsxref("Operators/yield", "yield")}} expression and finishes the generator.</dd>
<dt>{{jsxref("AsyncGenerator.prototype.throw()")}}</dt>
<dd>Returns a {{jsxref("Promise")}} that is rejected with an exception thrown from (or uncaught from) within the async generator function and finishes the generator unless the exception is caught within that generator.</dd>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a long and complicated sentence and could do with splitting into 2, probably at the "function and finishes" juncture. It's also not very clear how to parse "(or uncaught from)" or how that relates to "unless the exception is caught within that generator".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking about next and finishes make me think, whether a state chart might be helpful for comprehension.

</dl>

<h2 id="Examples">Examples</h2>

<h3 id="async_generator_iteration">Async generator iteration</h3>

<p>The following example iterates over an async generator logging values 1 - 6 to the console, at decreasing time intervals.</p>

<pre class="brush: js;">
function waitFor(time, value) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(value), time);
});
}

async function* generate() {
yield await waitFor(1000, 1);
yield await waitFor(2000, 2);
yield await waitFor(400, 3);
yield await waitFor(800, 4);
yield await waitFor(150, 5);
yield await waitFor(50, 6);
console.log('All done!');
}

async function main() {
for await (const value of generate()) {
console.log('value', value);
}
}

main()
.catch((e) => console.error('error', e));</pre>

<h2 id="Specifications">Specifications</h2>

{{Specifications}}

<h2 id="Browser_compatibility">Browser compatibility</h2>

<p>{{Compat}}</p>

<h2 id="See_also">See also</h2>

<ul>
<li>{{jsxref("Statements/function*", "function*", "", 1)}}</li>
<li>{{jsxref("Statements/async_function*", "async function*", "", 1)}}</li>
<li>{{jsxref("Operators/function*", '<code>function*</code> expression', "", 1)}}</li>
<li>{{jsxref("GeneratorFunction", "Generator Function", "", 1)}}</li>
<li>{{jsxref("AsyncGeneratorFunction", "Async Generator Function", "", 1)}}</li>
<li><a href="/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol">The Iterator protocol</a></li>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
title: AsyncGenerator.prototype.next()
slug: Web/JavaScript/Reference/Global_Objects/AsyncGenerator/next
tags:
- ECMAScript 2018
- AsyncGenerator
- JavaScript
- Method
- Prototype
- Reference
browser-compat: javascript.builtins.AsyncGenerator.next
---
<div>{{JSRef}}</div>

<p>The <strong><code>next()</code></strong> method returns the next value in the sequence.</p>

<h2 id="Syntax">Syntax</h2>

<pre class="brush: js">asyncGen.next()
asyncGen.next(value)</pre>

<h3 id="Parameters">Parameters</h3>

<dl>
<dt><code><var>value</var></code></dt>
<dd>An optional value used to modify the internal state of the generator. A value passed to the <code>next()</code> method will be received by <code>yield</code></dd>
</dl>

<h3 id="Return_value">Return value</h3>

<p>A {{jsxref("Promise")}} which when resolved returns an {{jsxref("Object")}} with two properties:</p>

<dl>
<dt><code>done</code></dt>
<dd>A {{jsxref("Boolean")}} value: <code>true</code> if the iterator is past the end of the iterated sequence. In this case <code>value</code> optionally specifies the <em>return value</em> of the iterator. <code>false</code> if the iterator was able to produce the next value in the sequence.</dd>
<dt><code>value</code></dt>
<dd>Any JavaScript value returned by the iterator. Can be omitted when <code>done</code> is <code>true</code>.</dd>
</dl>

<h2 id="Examples">Examples</h2>

<h3 id="Using_next">Using next()</h3>

<p>The following example shows a simple generator and the object that the <code>next</code> method returns:</p>

<pre class="brush: js">async function* createAsyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}

const asyncGen = createAsyncGenerator();
asyncGen.next().then(res => console.log(res)); // "Object { value: 1, done: false }"
asyncGen.next().then(res => console.log(res)); // "Object { value: 2, done: false }"
asyncGen.next().then(res => console.log(res)); // "Object { value: 3, done: false }"
asyncGen.next().then(res => console.log(res)); // "Object { value: undefined, done: true }"
</pre>

<h3 id="Sending_values_to_the_generator">Sending values to the generator</h3>

<p>In this example, <code>next</code> is called with a value.</p>

<div class="notecard note">
<p><strong>Note:</strong> The first call does not log anything, because the generator was not yielding anything initially.</p>
</div>


<pre class="brush: js">async function* createAsyncGenerator() {
while (true) {
let value = yield await Promise.resolve(null);
console.log(value);
}
}

const asyncGen = createAsyncGenerator();
asyncGen.next(1).then(res => console.log(res)); // { value: null, done: false }
asyncGen.next(2).then(res => console.log(res)); // { value: null, done: false }
</pre>

<h3 id="Using_next_with_a_list">Using next() with a list</h3>

<pre class="brush: js">async function* getPage(pageSize = 1, list) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit of a complex example that could benefit from a paragraph explaining what it's doing.

let output = [];
let index = 0;

while (index &lt; list.length) {
output = [];
for (let i = index; i &lt; index + pageSize; i++) {
if (list[i]) {
output.push(list[i]);
}
}

yield await Promise.resolve(output);
index += pageSize;
}
}

const list = [1, 2, 3, 4, 5, 6, 7, 8];
const page = getPage(3, list); // AsyncGenerator { }

page.next().then(res => console.log(res)); // Object { value: [1, 2, 3], done: false }
page.next().then(res => console.log(res)); // Object { value: [4, 5, 6], done: false }
page.next().then(res => console.log(res)); // Object { value: [7, 8], done: false }
page.next().then(res => console.log(res)); // Object { value: undefined, done: true }
</pre>



<h2 id="Specifications">Specifications</h2>

{{Specifications}}

<h2 id="Browser_compatibility">Browser compatibility</h2>

<p>{{Compat}}</p>

<h2 id="See_also">See also</h2>

<ul>
<li>{{jsxref("Statements/async_function*", "async function*")}}</li>
Rumyra marked this conversation as resolved.
Show resolved Hide resolved
<li><a href="/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators">Iterators and generators</a></li>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
title: AsyncGenerator.prototype.return()
slug: Web/JavaScript/Reference/Global_Objects/AsyncGenerator/return
tags:
- ECMAScript 2018
- AsyncGenerator
- JavaScript
- Method
- Prototype
- Reference
browser-compat: javascript.builtins.AsyncGenerator.return
---
<div>{{JSRef}}</div>

<p>The <strong><code>return()</code></strong> method returns the given value and finishes the generator.</p>

<h2 id="Syntax">Syntax</h2>

<pre class="brush: js">asyncGen.return(value)</pre>

<h3 id="Parameters">Parameters</h3>

<dl>
<dt><code><var>value</var></code></dt>
<dd>The value to return.</dd>
</dl>

<h3 id="Return_value">Return value</h3>

<p>Returns a {{jsxref("Promise")}} which resolves with the value that is given as an argument.</p>

<h2 id="Examples">Examples</h2>

<h3 id="Using_return">Using return()</h3>

<p>The following example shows a simple async generator and the <code>return</code> method.</p>

<pre class="brush: js">async function* createAsyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}

const asyncGen = createAsyncGenerator();

asyncGen.next().then(res => console.log(res)); // { value: 1, done: false }
asyncGen.return('foo').then(res => console.log(res)); // { value: "foo", done: true }
asyncGen.next().then(res => console.log(res)); // { value: undefined, done: true }
</pre>

<h3 id="Using_return_once_a_generator_is_complete">Using return() once a generator is complete</h3>

<p>If no <var>value</var> argument is passed into the <code>return()</code> method, the promise will resolve as if the <a href="">next()</a> method has been called. In this example the generator has completed, so the value returned is <code>undefined</code>.</p>

<p><code>return()</code> can still be called after the generator is in a "completed" state, however the generator will stay in this state.</p>

<pre class="brush: js">async function* createAsyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}

const asyncGen = createAsyncGenerator();

asyncGen.next().then(res => console.log(res)); // { value: 1, done: false }
asyncGen.next().then(res => console.log(res)); // { value: 2, done: false }
asyncGen.next().then(res => console.log(res)); // { value: 3, done: false }

// value is returned undefined, as no value is passed and generator is 'done'
asyncGen.return().then(res => console.log(res)); // { value: undefined, done: true }

// we can still return a value once the generator is complete
asyncGen.return(1).then(res => console.log(res)); // { value: 1, done: true }
</pre>

<h2 id="Specifications">Specifications</h2>

{{Specifications}}

<h2 id="Browser_compatibility">Browser compatibility</h2>

<p>{{Compat}}</p>

<h2 id="See_also">See also</h2>

<ul>
<li>{{jsxref("Statements/async_function*", "async function*")}}</li>
Rumyra marked this conversation as resolved.
Show resolved Hide resolved
<li><a href="/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators">Iterators and generators</a></li>
</ul>
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: AsyncGenerator.prototype.throw()
slug: Web/JavaScript/Reference/Global_Objects/AsyncGenerator/throw
tags:
- ECMAScript 2018
- AsyncGenerator
- JavaScript
- Method
- Prototype
- Reference
browser-compat: javascript.builtins.AsyncGenerator.throw
---
<div>{{JSRef}}</div>

<p>The <strong><code>throw()</code></strong> method forces a generator to throw an exception.</p>

<h2 id="Syntax">Syntax</h2>

<pre class="brush: js">asyncGen.throw(exception)</pre>

<h3 id="Parameters">Parameters</h3>

<dl>
<dt><code><var>exception</var></code></dt>
<dd>The exception to throw. For debugging purposes, it is useful to make it an <code>instanceof</code> {{jsxref("Error")}}.</dd>
</dl>

<h3 id="Return_value">Return value</h3>

<p>A {{jsxref("Promise")}} which when resolved returns an {{jsxref("Object")}} with two properties:</p>

<dl>
<dt><code>done</code></dt>
<dd>A {{jsxref("Boolean")}} value: <code>true</code> if the iterator is past the end of the iterated sequence. In this case <code>value</code> optionally specifies the <em>return value</em> of the iterator. <code>false</code> if the iterator was able to produce the next value in the sequence.</dd>
<dt><code>value</code></dt>
<dd>Any JavaScript value returned by the iterator. Can be omitted when <code>done</code> is <code>true</code>.</dd>
</dl>

<h2 id="Examples">Examples</h2>

<h3 id="Using_throw">Using throw()</h3>

<p>The following example shows a simple generator and an error that is thrown using the <code>throw</code> method. An error can be caught by a {{jsxref("Statements/try...catch", "try...catch")}} block as usual.</p>

<pre class="brush: js">async function* createAsyncGenerator() {
while(true) {
try {
yield 42;
} catch(e) {
console.log(new Error(e));
}
}
}

const asyncGen = createAsyncGenerator();
asyncGen.next(1).then(res => console.log(res)); // { value: 42, done: false }
asyncGen.throw(new Error('Something went wrong')) // Error: 'Error: Something went wrong
.then(res => console.log(res)); // { value: 42, done: false }
</pre>

<h2 id="Specifications">Specifications</h2>

{{Specifications}}

<h2 id="Browser_compatibility">Browser compatibility</h2>

<p>{{Compat}}</p>

<h2 id="See_also">See also</h2>

<ul>
<li>{{jsxref("Statements/async_function*", "async function*")}}</li>
Rumyra marked this conversation as resolved.
Show resolved Hide resolved
<li><a href="/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators">Iterators and generators</a></li>
</ul>
Loading