Async-Funktionen , eine Funktion in ES2017 , sorgen dafür , dass Async-Code mithilfe von Versprechungen (einer bestimmten Form von Async-Code) und dem await
Schlüsselwort synchronisiert aussieht . Beachten Sie auch in den Codebeispielen unter dem Schlüsselwort async
vor dem function
Schlüsselwort, das eine asynchrone / wartende Funktion kennzeichnet. Das await
Schlüsselwort funktioniert nicht, ohne in einer Funktion zu sein, die mit dem async
Schlüsselwort voreingestellt ist . Da es derzeit keine Ausnahme gibt, bedeutet dies, dass keine Wartezeiten der obersten Ebene funktionieren (Wartezeiten der obersten Ebene bedeuten ein Warten außerhalb einer Funktion). Es gibt jedoch einen Vorschlag für die oberste Ebeneawait
.
ES2017 wurde am 27. Juni 2017 als Standard für JavaScript ratifiziert (dh finalisiert). Async await funktioniert möglicherweise bereits in Ihrem Browser. Andernfalls können Sie die Funktionalität weiterhin mit einem Javascript-Transpiler wie babel oder traceur verwenden . Chrome 55 bietet volle Unterstützung für asynchrone Funktionen. Wenn Sie also einen neueren Browser haben, können Sie möglicherweise den folgenden Code ausprobieren.
Siehe kangax des es2017 Kompatibilitätstabelle für Browser - Kompatibilität.
Hier ist ein Beispiel für eine asynchrone Wartefunktion, doAsync
die drei Pausen von einer Sekunde benötigt und die Zeitdifferenz nach jeder Pause ab der Startzeit ausgibt:
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
async function doAsync () {
var start = Date.now(), time;
console.log(0);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
time = await doSomethingAsync();
console.log(time - start);
}
doAsync();
Wenn das Schlüsselwort await vor einem Versprechungswert steht (in diesem Fall ist der Versprechenswert der von der Funktion doSomethingAsync zurückgegebene Wert), pausiert das Schlüsselwort await die Ausführung des Funktionsaufrufs, hält jedoch keine anderen Funktionen an und fährt fort Ausführen von anderem Code, bis das Versprechen aufgelöst ist. Nachdem das Versprechen aufgelöst wurde, wird der Wert des Versprechens ausgepackt, und Sie können sich vorstellen, dass der Ausdruck Warten und Versprechen jetzt durch diesen ausgepackten Wert ersetzt wird.
Da das Warten nur pausiert und wartet, wird dann ein Wert entpackt, bevor der Rest der Zeile ausgeführt wird. Sie können ihn für Schleifen und interne Funktionsaufrufe wie im folgenden Beispiel verwenden, in dem die in einem Array erwarteten Zeitunterschiede erfasst und das Array ausgedruckt werden.
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this calls each promise returning function one after the other
async function doAsync () {
var response = [];
var start = Date.now();
// each index is a promise returning function
var promiseFuncs= [doSomethingAsync, doSomethingAsync, doSomethingAsync];
for(var i = 0; i < promiseFuncs.length; ++i) {
var promiseFunc = promiseFuncs[i];
response.push(await promiseFunc() - start);
console.log(response);
}
// do something with response which is an array of values that were from resolved promises.
return response
}
doAsync().then(function (response) {
console.log(response)
})
Die asynchrone Funktion selbst gibt ein Versprechen zurück, sodass Sie dieses als Versprechen mit Verkettung verwenden können, wie ich es über oder innerhalb einer anderen asynchronen Wartefunktion tue.
Die obige Funktion wartet auf jede Antwort, bevor eine weitere Anfrage gesendet wird . Wenn Sie die Anfragen gleichzeitig senden möchten, können Sie Promise.all verwenden .
// no change
function timeoutPromise (time) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(Date.now());
}, time)
})
}
// no change
function doSomethingAsync () {
return timeoutPromise(1000);
}
// this function calls the async promise returning functions all at around the same time
async function doAsync () {
var start = Date.now();
// we are now using promise all to await all promises to settle
var responses = await Promise.all([doSomethingAsync(), doSomethingAsync(), doSomethingAsync()]);
return responses.map(x=>x-start);
}
// no change
doAsync().then(function (response) {
console.log(response)
})
Wenn das Versprechen möglicherweise abgelehnt wird, können Sie es in einen Try-Catch einschließen oder den Try-Catch überspringen und den Fehler auf den Catch-Aufruf der asynchronen / wait-Funktionen übertragen. Sie sollten darauf achten, Versprechungsfehler nicht unbehandelt zu lassen, insbesondere in Node.js. Im Folgenden finden Sie einige Beispiele, die zeigen, wie Fehler funktionieren.
function timeoutReject (time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error("OOPS well you got an error at TIMESTAMP: " + Date.now()));
}, time)
})
}
function doErrorAsync () {
return timeoutReject(1000);
}
var log = (...args)=>console.log(...args);
var logErr = (...args)=>console.error(...args);
async function unpropogatedError () {
// promise is not awaited or returned so it does not propogate the error
doErrorAsync();
return "finished unpropogatedError successfully";
}
unpropogatedError().then(log).catch(logErr)
async function handledError () {
var start = Date.now();
try {
console.log((await doErrorAsync()) - start);
console.log("past error");
} catch (e) {
console.log("in catch we handled the error");
}
return "finished handledError successfully";
}
handledError().then(log).catch(logErr)
// example of how error propogates to chained catch method
async function propogatedError () {
var start = Date.now();
var time = await doErrorAsync() - start;
console.log(time - start);
return "finished propogatedError successfully";
}
// this is what prints propogatedError's error.
propogatedError().then(log).catch(logErr)
Wenn du hierher gehst Sie die fertigen Vorschläge für kommende ECMAScript-Versionen.
Eine Alternative dazu, die nur mit ES2015 (ES6) verwendet werden kann, ist die Verwendung einer speziellen Funktion, die eine Generatorfunktion umschließt. Generatorfunktionen verfügen über ein Yield-Schlüsselwort, mit dem das Schlüsselwort await mit einer umgebenden Funktion repliziert werden kann. Das Yield-Schlüsselwort und die Generatorfunktion sind viel allgemeiner und können viel mehr als das, was die asynchrone Wartefunktion tut. Wenn Sie einen Generatorfunktions-Wrapper benötigen , der zum Replizieren von asynchronem Warten verwendet werden kann, würde ich co.js überprüfen . Übrigens, die Funktion von co, ähnlich wie die asynchronen Wartefunktionen, gibt ein Versprechen zurück. Ehrlich gesagt ist die Browserkompatibilität zu diesem Zeitpunkt sowohl für Generatorfunktionen als auch für Async-Funktionen ungefähr gleich. Wenn Sie also nur die Async-Wait-Funktion wünschen, sollten Sie Async-Funktionen ohne co.js verwenden.
Die Browserunterstützung ist jetzt für Async-Funktionen (Stand 2017) in allen gängigen Browsern (Chrome, Safari und Edge) mit Ausnahme des IE ziemlich gut.