Funkcje asynchroniczne umożliwiają pisanie kodu opartego na obietnicach tak, jakby był on synchroniczny.
Funkcje asynchroniczne są domyślnie włączone w przeglądarkach Chrome, Edge, Firefox i Safari. są naprawdę cudowne. Umożliwiają one pisanie kodu opartego na obietnicach gdyby był synchroniczny, ale bez blokowania wątku głównego. Sprawiają, że kod asynchroniczny mniej „inteligentny” i bardziej czytelny.
Funkcje asynchroniczne działają w ten sposób:
async function myFirstAsyncFunction() {
try {
const fulfilledValue = await promise;
} catch (rejectedValue) {
// …
}
}
Jeśli użyjesz słowa kluczowego async
przed definicją funkcji, możesz użyć funkcji
await
w funkcji. Gdy await
obiecuje, funkcja jest wstrzymywana
w sposób nieblokujący, dopóki się nie obiecuje. Jeśli obietnica się spełni,
odzyskać wartość. Jeśli obietnica odrzuci wartość, jest wyświetlana odrzucona wartość.
Obsługa przeglądarek
Przykład: rejestrowanie pobierania
Załóżmy, że chcesz pobrać adres URL i zapisać odpowiedź jako tekst. Wygląd za pomocą obietnic:
function logFetch(url) {
return fetch(url)
.then((response) => response.text())
.then((text) => {
console.log(text);
})
.catch((err) => {
console.error('fetch failed', err);
});
}
To samo przy użyciu funkcji asynchronicznych:
async function logFetch(url) {
try {
const response = await fetch(url);
console.log(await response.text());
} catch (err) {
console.log('fetch failed', err);
}
}
Liczba wierszy jest taka sama, ale wszystkie wywołania zwrotne zniknęły. Dzięki temu zwłaszcza dla osób mniej obeznanych z obietnicami.
Asynchroniczne wartości zwracane
Funkcje asynchroniczne zawsze zwracają obietnicę, niezależnie od tego, czy używasz await
. Ten
obiecuje rozwiązuje się z każdym zwracaniem funkcji asynchronicznej lub odrzuca z argumentem
niezależnie od tego, co generuje funkcja asynchroniczna. A więc:
// wait ms milliseconds
function wait(ms) {
return new Promise((r) => setTimeout(r, ms));
}
async function hello() {
await wait(500);
return 'world';
}
...wywołanie hello()
zwraca obietnicę spełniającą wartość "world"
.
async function foo() {
await wait(500);
throw Error('bar');
}
...wywołanie foo()
zwraca obietnicę odrzucającą z funkcją Error('bar')
.
Przykład: przesyłanie strumieniowe odpowiedzi
W bardziej złożonych przykładach korzyści zapewniają funkcje asynchroniczne. Powiedz, że chcesz , aby przesyłać strumieniowo odpowiedź przy jednoczesnym wylogowywaniu fragmentów, i zwracaniu ostatecznego rozmiaru.
Oto obietnice:
function getResponseSize(url) {
return fetch(url).then((response) => {
const reader = response.body.getReader();
let total = 0;
return reader.read().then(function processResult(result) {
if (result.done) return total;
const value = result.value;
total += value.length;
console.log('Received chunk', value);
return reader.read().then(processResult);
});
});
}
Obejrzyjcie mnie, Jake „wielder obietnic” Archibald. Zobacz, jak dzwonię
processResult()
w środku, aby skonfigurować pętlę asynchroniczną? Historie autorstwa
że czuję się bardzo mądra. Ale jak większość „inteligentnych” w kodzie, trzeba się na niego patrzeć
aby dowiedzieć się, co ona robi, na przykład jedno z tych zdjęć
lata 90.
Spróbujmy jeszcze raz z funkcjami asynchronicznymi:
async function getResponseSize(url) {
const response = await fetch(url);
const reader = response.body.getReader();
let result = await reader.read();
let total = 0;
while (!result.done) {
const value = result.value;
total += value.length;
console.log('Received chunk', value);
// get the next result
result = await reader.read();
}
return total;
}
Wszystkie „inteligentne” już nie ma aplikacji. Asynchroniczna pętla, która sprawiła, że poczułam się tak rozbawiona.
godne zaufania, nudne, „pętla”. Dużo lepiej. W przyszłości możesz
iteratory asynchroniczne,
co spowodowałoby
Zastąp pętlę while
pętlą for-of-of, aby stała się jeszcze czystsza.
Inna składnia funkcji asynchronicznej
Widzieliśmy już słowo async function() {}
, ale słowo kluczowe async
może być bardziej
używany z inną składnią funkcji:
Funkcje strzałek
// map some URLs to json-promises
const jsonPromises = urls.map(async (url) => {
const response = await fetch(url);
return response.json();
});
Metody obiektów
const storage = {
async getAvatar(name) {
const cache = await caches.open('avatars');
return cache.match(`/avatars/${name}.jpg`);
}
};
storage.getAvatar('jaffathecake').then(…);
Metody zajęć
class Storage {
constructor() {
this.cachePromise = caches.open('avatars');
}
async getAvatar(name) {
const cache = await this.cachePromise;
return cache.match(`/avatars/${name}.jpg`);
}
}
const storage = new Storage();
storage.getAvatar('jaffathecake').then(…);
Ostrożnie! Unikaj zbyt sekwencyjnego działania
Chociaż piszesz kod, który wygląda na synchroniczny, upewnij się, że nie został pominięty że możemy robić różne rzeczy równolegle.
async function series() {
await wait(500); // Wait 500ms…
await wait(500); // …then wait another 500ms.
return 'done!';
}
Ten proces zajmuje 1000 ms, a w przypadku:
async function parallel() {
const wait1 = wait(500); // Start a 500ms timer asynchronously…
const wait2 = wait(500); // …meaning this timer happens in parallel.
await Promise.all([wait1, wait2]); // Wait for both timers in parallel.
return 'done!';
}
Ukończenie tego procesu zajmuje 500 ms, ponieważ oba oczekiwania odbywają się w tym samym czasie. Spójrzmy na przykład praktyczny.
Przykład: pobieranie danych w określonej kolejności
Załóżmy, że chcesz pobrać serię adresów URL i jak najszybciej je zapisać w w prawidłowej kolejności.
Głęboki oddech – tak z obietnictwem:
function markHandled(promise) {
promise.catch(() => {});
return promise;
}
function logInOrder(urls) {
// fetch all the URLs
const textPromises = urls.map((url) => {
return markHandled(fetch(url).then((response) => response.text()));
});
// log them in order
return textPromises.reduce((chain, textPromise) => {
return chain.then(() => textPromise).then((text) => console.log(text));
}, Promise.resolve());
}
Tak, używam funkcji reduce
do łączenia sekwencji obietnic. jestemwięc
. Jednak ta technika kodowania jest tak mądra, bez której nie da się już sobie poradzić.
Jednak przy konwertowaniu powyższych ustawień na funkcję asynchroniczną, kusi zbyt sekwencyjna:
async function logInOrder(urls) { for (const url of urls) { const response = await fetch(url); console.log(await response.text()); } }
function markHandled(...promises) { Promise.allSettled(promises); } async function logInOrder(urls) { // fetch all the URLs in parallel const textPromises = urls.map(async (url) => { const response = await fetch(url); return response.text(); }); markHandled(...textPromises); // log them in sequence for (const textPromise of textPromises) { console.log(await textPromise); } }
Obejście obsługi przeglądarki: generatory
Jeśli kierujesz reklamy na przeglądarki, które obsługują generatory (w tym najnowszej wersji każdej popularnej przeglądarki ), możesz posortować funkcje asynchroniczne polyfill.
Babel zrobi to za Ciebie, Oto przykład pochodzący z Babel REPL
- na ile podobny jest kod po transpilacji. To przekształcenie jest częścią Gotowe ustawienia es2017 Babel.
Zalecamy metodę transpilacji, ponieważ można ją po prostu wyłączyć, docelowe przeglądarki obsługują funkcje asynchroniczne, ale jeśli naprawdę nie chcesz używać funkcji można pobrać kod polyfill Babel's i używać ich samodzielnie. Zamiast:
async function slowEcho(val) {
await wait(1000);
return val;
}
...użyj kodu polyfill i wpisz:
const slowEcho = createAsyncFunction(function* (val) {
yield wait(1000);
return val;
});
Pamiętaj, że musisz przekazać generatora (function*
) do: createAsyncFunction
,
i użyj yield
zamiast await
. W przeciwnym razie wszystko działa tak samo.
Obejście problemu: regenerator
Jeśli kierujesz kampanię na starsze przeglądarki, Babel może również transpilować generatory, co pozwala korzystać z funkcji asynchronicznych aż do IE8. Aby to zrobić, musisz: Gotowe ustawienia Babel es2017 oraz gotowe ustawienia es2015.
Wyniki nie są tak atrakcyjne, więc uważaj, i nadużywać kodu.
Wszystkie funkcje.
Gdy funkcje asynchroniczne pojawią się we wszystkich przeglądarkach, używaj ich funkcja zwracająca obietnicę! Nie tylko upraszczają one kod, upewnij się, że ta funkcja zawsze zwróci obietnicę.
Bardzo spodobały mi się funkcje asynchroniczne 2014 oraz dobrze jest widzieć, jak lądują w przeglądarkach. Oj!