Funkcje asynchroniczne , funkcja w ES2017 , sprawiają, że kod asynchroniczny wygląda na zsynchronizowany przy użyciu obietnic (szczególnej formy kodu asynchronicznego) i await
słowa kluczowego. Zwróć też uwagę na przykłady kodu poniżej słowa kluczowego async
przed function
słowem kluczowym, które oznacza funkcję asynchroniczną / oczekującą. Słowo await
kluczowe nie będzie działać bez funkcji wstępnie ustawionej za pomocą async
słowa kluczowego. Ponieważ obecnie nie ma wyjątku od tego, co oznacza, że nie będzie oczekiwał żaden poziom najwyższy (poziom najwyższy czeka, co oznacza oczekiwanie poza jakąkolwiek funkcją). Chociaż jest propozycja na najwyższym poziomieawait
.
ES2017 został ratyfikowany (tj. Sfinalizowany) jako standard dla JavaScript w dniu 27 czerwca 2017 r. Async oczekuje może już działać w przeglądarce, ale jeśli nie, nadal możesz korzystać z tej funkcji za pomocą transpilatora javascript, takiego jak babel lub traceur . Chrome 55 ma pełne wsparcie funkcji asynchronicznych. Jeśli masz nowszą przeglądarkę, możesz wypróbować poniższy kod.
Zobacz tabelę zgodności kangax es2017 dla kompatybilności przeglądarki.
Oto przykładowa wywoływana funkcja asynchroniczna, doAsync
która wymaga trzech jednosekundowych pauz i drukuje różnicę czasu po każdej pauzie od czasu rozpoczęcia:
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();
Po umieszczeniu słowa kluczowego oczekującego przed wartością przyrzeczenia (w tym przypadku wartością przyrzeczenia jest wartość zwrócona przez funkcję doSomethingAsync) słowo kluczowe oczekujące wstrzyma wykonanie wywołania funkcji, ale nie wstrzyma żadnych innych funkcji i będzie kontynuowane wykonywanie innego kodu, dopóki obietnica nie zostanie rozwiązana. Po spełnieniu obietnicy odwija wartość obietnicy i możesz pomyśleć o wyrażeniu oczekiwania i obietnicy, które jest teraz zastępowane przez tę nieopakowaną wartość.
Tak więc, ponieważ czekanie tylko pauza czeka, a następnie rozpakowuje wartość przed wykonaniem reszty linii, możesz użyć jej do pętli i wywołań funkcji wewnętrznych, jak w poniższym przykładzie, który zbiera oczekiwane różnice czasowe w tablicy i drukuje tablicę.
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)
})
Sama funkcja asynchroniczna zwraca obietnicę, dzięki czemu można jej użyć jako obietnicy z łańcuchem takim jak ja powyżej lub w innej funkcji oczekującej asynchronizacji.
Funkcja powyżej czekałaby na każdą odpowiedź przed wysłaniem kolejnego żądania, jeśli chcesz wysłać żądania jednocześnie, możesz użyć Promise.all .
// 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)
})
Jeśli obietnica prawdopodobnie zostanie odrzucona, możesz zawinąć ją w try catch lub pomiń try catch i pozwolić, aby błąd rozprzestrzenił się na wywołanie funkcji async / oczekuj. Należy uważać, aby nie pozostawić nieobsługiwanych błędów obietnicy, szczególnie w Node.js. Poniżej kilka przykładów, które pokazują, jak działają błędy.
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)
Jeśli pójdziesz tutaj , możesz zobaczyć gotowe propozycje przyszłych wersji ECMAScript.
Alternatywą dla tego, która może być używana tylko z ES2015 (ES6), jest użycie specjalnej funkcji, która otacza funkcję generatora. Funkcje generatora mają słowo kluczowe wydajności, które może być użyte do replikacji słowa kluczowego oczekującego z funkcją otaczającą. Słowo kluczowe wydajności i funkcja generatora są znacznie bardziej ogólne i mogą robić znacznie więcej niż tylko to, co robi funkcja asynchroniczna. Jeśli chcesz otoki funkcji generatora, której można użyć do replikacji asynchronizacji, czekam co.js . Nawiasem mówiąc, funkcja co podobnie jak async oczekuje na funkcje zwracające obietnicę. Szczerze mówiąc, w tym momencie kompatybilność przeglądarki jest prawie taka sama zarówno dla funkcji generatora, jak i funkcji asynchronicznych, więc jeśli chcesz, aby funkcja async oczekiwała funkcjonalności, powinieneś używać funkcji asynchronicznych bez co.js.
Obsługa przeglądarek jest teraz całkiem dobra dla funkcji Async (od 2017 r.) We wszystkich głównych przeglądarkach (Chrome, Safari i Edge) z wyjątkiem IE.