-
Notifications
You must be signed in to change notification settings - Fork 22.5k
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
Changes from all commits
6de1a35
a8d56b1
ef06d6e
c1a2f09
cff7b5d
d38696c
77c1e75
15a51eb
658a2b4
ccfa77d
dddfb8a
ee4aca0
033ba8f
1ab12a5
76a0bb5
d58fe42
c331788
c6f5f6e
cf479a0
0c8af2e
0d1ab7a
f0be1e2
0786efa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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> | ||
|
||
<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> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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". There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 < list.length) { | ||
output = []; | ||
for (let i = index; i < 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> |
There was a problem hiding this comment.
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