1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
---
title: async function
slug: Web/JavaScript/Reference/Statements/async_function
tags:
- Example
- JavaScript
translation_of: Web/JavaScript/Reference/Statements/async_function
---
<div>
<div>{{jsSidebar("Statements")}}</div>
<p><span class="seoSummary"> Die <code><strong>async function</strong></code> Deklaration definiert eine <strong>asynchrone Funktion</strong>, die ein {{jsxref("Global_Objects/AsyncFunction","AsyncFunction")}} Objekt zurück gibt.</span> Asynchrone Funktionen laufen über den <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop">Event Loop</a> außerhalb des üblichen Kontrollflusses, und geben als Ergebnis ein implizites {{jsxref("Promise")}} Objekt zurück. Die Syntax und der Aufbau des Codes bei einer asynchronen Funktion ähnelt allerdings der den standardmässigen synchronen Funktionen.</p>
<div class="noinclude">
<p>Eine <strong><code>async function</code></strong> kann auch durch den {{jsxref("Operators/async_function", "async function expression", "", 1)}} Ausdruck definiert werden.</p>
</div>
</div>
<div>{{EmbedInteractiveExample("pages/js/statement-async.html", "taller")}}</div>
<p class="hidden">The source for this interactive demo is stored in a GitHub repository. If you'd like to contribute to the interactive demo project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p>
<h2 id="Syntax">Syntax</h2>
<pre class="syntaxbox">async function <em>name</em>([<em>param</em>[, <em>param</em>[, ... <em>param</em>]]]) {
<em>statements</em>
}
</pre>
<h3 id="Die_Parameter">Die Parameter</h3>
<dl>
<dt><code>name</code></dt>
<dd>Der Name der Funktion.</dd>
</dl>
<dl>
<dt><code>param</code></dt>
<dd>Der Name eines Arguments, welches der Funktion übergeben wird.</dd>
</dl>
<dl>
<dt><code>statements</code></dt>
<dd>Die Ausdrücke, aus denen der Funktionskörper besteht.</dd>
</dl>
<h3 id="Der_zurückgegebene_Wert">Der zurückgegebene Wert</h3>
<p>Ein <code><a href="https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a></code> Objekt. Das Promise wird entweder mit dem zurück gelieferten Wert der asnychronen Funktion eingehalten (Engl: "resolved"), oder mit einem unbehandelten Fehler innerhalb der asynchronen Funktion verworfen (Engl: "rejected").</p>
<h2 id="Beschreibung">Beschreibung</h2>
<p>Eine <code>async</code> Funktion darf einen {{jsxref("Operators/await", "await")}} Ausdruck enthalten, der die Ausführung der asynchronen Funktion anhält. Die Funktion wartet auf die Entscheidung des übergebenen <code>Promise</code>, setzt dann die Ausführung der asynchronen Funktionen fort und wird als eingehaltener (Engl: "resolved") Wert ausgewertet.</p>
<p><strong>Das Schlüsselwort <code>await</code> gilt nur innerhalb der <code>async</code> Funktionen.</strong> Die Verwendung außerhalb solcher Funktion wirft einen <code><a href="/de/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError">SyntaxError</a></code> auf.</p>
<div class="note">
<p>Das Ziel der <code>async</code>/<code>await</code> Funktionen ist zweifach. Erstens vereinfachen sie die Anwendung von <code>Promises</code> im Rahmen eines synchronen Verfahrens. Zweitens ermöglichen sie die kollektive Verarbeitung einer Gruppe von <code>Promises</code>. Genau wie die <code>Promises</code> dem Verhalten von callbacks ("Rückruffunktionen") ähneln, so ähnelt die <code>async</code>/<code>await</code> Methode der Zusammensetzung von <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators">Generatoren</a> und <code>Promises</code>.</p>
</div>
<h2 id="Beispiele">Beispiele</h2>
<h3 id="Einfaches_Beispiel">Einfaches Beispiel</h3>
<pre class="brush: js">var resolveAfter2Seconds = function() {
//nach 2 Sek. einlösen
console.log("langsames Promise beginnt");
return new Promise(resolve => {
setTimeout(function() {
resolve(20); //"20" taucht als der zurückgegebene Wert der Fkn. auf
console.log("langsames Promise fertig");
}, 2000);
});
};
var resolveAfter1Second = function() {
//nach 1 Sek. einlösen
console.log("schnelles Promise beginnt");
return new Promise(resolve => {
setTimeout(function() {
resolve(10); //"10" taucht als der zurückgegebene Wert der Fkn. auf
console.log("schnelles Promise fertig");
}, 1000);
});
};
var sequentialStart = async function() {
console.log('==NACHEINANDER STARTEN==');
// Falls der dem await Operator folgende Ausdruck kein Promise ist,
// wird jener Ausdruck in ein eingehaltenes ("resolved") Promise umgewandelt
// 1. die Ausführung erfolgt fast sofort
const slow = await resolveAfter2Seconds();
console.log(slow); // 2. das hier startet 2 Sekunden nach 1.
const fast = await resolveAfter1Second();
console.log(fast); // 3. das hier startet 3 Sekunden nach 1.
}
var concurrentStart = async function() {
console.log('==ZEITGLEICH ANFANGEN mit await==');
const slow = resolveAfter2Seconds(); // startet den Timer sofort
const fast = resolveAfter1Second(); // startet den Timer sofort
// 1. die Ausführung erfolgt fast sofort
console.log(await slow); // 2. das hier startet 2 Sekunden nach 1.
console.log(await fast); // 3. das hier startet 2 Sekunden nach 1., also sofort nach 2., da "fast" bereits aufgelöst ist
}
var stillConcurrent = function() {
console.log('==ZEITGLEICH ANFANGEN mit Promise.all==');
Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => {
console.log(messages[0]); // "slow"
console.log(messages[1]); // "fast"
});
}
var parallel = function() {
console.log('==PARALLEL mit Promise.then==');
resolveAfter2Seconds().then((message)=>console.log(message));
resolveAfter1Second().then((message)=>console.log(message));
}
sequentialStart(); // loggt "slow" nach 2 Sek., dann "fast" nach einer weiteren Sek.
// wartet, bis das obige Verfahren abschließt
setTimeout(concurrentStart, 4000); // loggt nach 2 Sek. erst "slow", dann "fast"
// wieder warten
setTimeout(stillConcurrent, 7000); // genau wie concurrentStart
// wieder warten
setTimeout(parallel, 10000); // echt parallel: loggt "fast" nach 1 Sek., dann "slow" nach einer weiteren Sek.
</pre>
<h4 id="await_und_Parallelität"><code>await</code> und Parallelität</h4>
<p>In der Funktion <code>sequentialStart</code> wird die Ausführung wegen dem ersten <code>await</code> für 2 Sekunden angehalten, und dann nochmal eine weitere Sekunde wegen dem zweiten <code>await</code>. Der zweite Timer wird erst erzeugt, sobald der erste durch ist, daher wird der Code nach 3 Sekunden durchgelaufen sein.</p>
<p>In der Funktion <code>concurrentStart</code> werden beide Timer erzeugt und dann darauf gewartet (<code>await</code>). Die beiden Timer laufen zur selben Zeit, was bedeutet, dass der Code in 2 Sekunden statt 3 durchläuft, also wie der langsamste Timer. Trotzdem laufen die <code>await</code> Aufrufe immer noch nacheinander, was bedeutet, dass das zweite <code>await</code> auf das Ende des ersten Timers warten wird. In diesem Fall wird das Ergebnis des schnellsten Timers erst nach dem des langsamsten Timers verarbeitet.</p>
<p>Wenn du wirklich zwei oder mehr Jobs gleichzeitig, also parallel, ausführen willst, musst du <code>await Promise.all([job1(), job2()])</code> wie in der <code>parallel</code> Funktion gezeigt verwenden.</p>
<div class="warning">
<h4 id="Merke_await_mit_Promisethen_nicht_verwechseln">Merke: <code>await</code> mit <code>Promise#then</code> nicht verwechseln</h4>
<p>Bei <code>sequentialStart</code> wird die Programmausführung auf 2 Sek. aufgehalten wegen des ersten <code>await</code>, dann wieder auf 1 Sek. wegen des zweiten <code>await</code>. Die zweite Stoppuhr wird erst nach Ablauf der ersten Stoppuhr erstellt.</p>
<p>Bei <code>concurrentStart</code> werden beide Stoppuhren gleichzeitig erstellt, dann in <code>await</code> versetzt. Obwohl beide Uhren nebeneinander laufen, laufen die <code>await</code> Abrufe serienweise. Das bedeutet, dass die zweite <code>await</code> Anweisung auf Ablauf der ersten wartet. Die Laufzeit dieses Abschnitts lautet daher 2--nicht 3--Sekunden, weil das langsamere Verfahren 2 Sek. braucht. Das Gleiche ereignet sich bei <code>stillConcurrent</code>, welcher Abschnitt die <code>Promise.all</code> Methode verwendet.</p>
<p>Wenn man auf mehrfache <code>Promises</code> parallel warten (<code>await</code>) will, muss man <code>Promise#then</code> verwenden, gerade wie die <code>parallel</code> Funktion am Ende dieses Beispiels.</p>
</div>
<h3 id="Umschreiben_einer_Promise-Kette_mittels_einer_async_Funktion">Umschreiben einer Promise-Kette mittels einer <code>async</code> Funktion</h3>
<p>Eine API die ein {{jsxref("Promise")}} zurückgibt resultiert in einer vielteiligen Promise-Kette. Man beachte den folgenden Code:</p>
<pre class="brush: js">function getProcessedData(url) {
return downloadData(url) // returns a promise
.catch(e => {
return downloadFallbackData(url) // returns a promise
})
.then(v => {
return processDataInWorker(v); // returns a promise
});
}
</pre>
<p>das kann mit einer <code>async</code> Funktion folgendermaßen umgeschrieben werden:</p>
<pre class="brush: js">async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch(e) {
v = await downloadFallbackData(url);
}
return processDataInWorker(v);
}
</pre>
<p>Im obigen Beispiel ist zu beachten, dass es keinen <code>await</code> Ausdruck auf dem <code>return</code> Ausdruck gibt, weil der Rückgabewert einer <code>async function</code> implizit im {{jsxref("Promise.resolve")}} eingeschlossen ist.</p>
<h2 id="Spezifikationen">Spezifikationen</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('ESDraft', '#sec-async-function-definitions', 'async function')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td>Initial definition in ES2017.</td>
</tr>
<tr>
<td>{{SpecName('ES8', '#sec-async-function-definitions', 'async function')}}</td>
<td>{{Spec2('ES8')}}</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="Browserkompatibilität">Browserkompatibilität</h2>
<div>
<p>{{Compat("javascript.statements.async_function")}}</p>
</div>
<h2 id="Siehe_auch">Siehe auch</h2>
<ul>
<li>{{jsxref("Operators/async_function", "async function expression")}}</li>
<li>{{jsxref("AsyncFunction")}} object</li>
<li>{{jsxref("Operators/await", "await")}}</li>
<li><a href="http://innolitics.com/10x/javascript-decorators-for-promise-returning-functions/">"Decorating Async Javascript Functions" on "innolitics.com"</a></li>
</ul>
|