JavaScript wykonał wielki krok na drodze do wielkości w pracy asynchronicznej. Najpierw były callbacki i ich piekiełko, na które wiele osób narzekało. Później przyszły promisy, których wiele osób nie rozumiało. Właśnie przez to niezrozumienie postanowiono uprościć async jeszcze bardziej. I tak właśnie w ES2017 dodano async/await. Zobacz, dlaczego jest to wielka zmiana.

Async/await jest połączeniem promisów i generatorów, i można je nazwać wyższym poziomem abstrakcji nad promisami. Znacznie upraszcza składnię zapytań asynchronicznych oraz zwiększa czytelność kodu. Ułatwia też debugowanie, czyniąc je takim samym jak w kodzie synchronicznym.

Najprostszy przykład:

const zrobCos = async () => {
  console.log('start');
  const zmienna = await funkcjaAsynchroniczna();
  console.log(zmienna);
  console.log('koniec');
}

Zauważ słowa kluczowe: async i await. Słowo async w uproszczeniu oznacza, że dana funkcja będzie wykonywana asynchronicznie, a słowo await- że w tym miejscu kod musi poczekać na wykonanie asynchroniczne, i dopiero po jego wykonaniu kod wykona się dalej. Właśnie dlatego konsola wypisze po kolei ‘start’, zawartość zmiennej i ‘koniec’, a nie błąd. 

Wróćmy jeszcze na chwilę do słówka async. Sprawia ono, że dana funkcja zwraca promisa, nawet jeżeli zwracasz coś innego. Dlatego też poniższy kod jest działający:

const funkcja = async () => { return ‘napis’ }
funkcja.then(console.log) // Kod wypisze w konsoli ‘napis’

I działa dokładnie tak samo, jak:

const funkcja = () => { return Promise.resolve(‘napis’) }
funkcja.then(console.log) // Kod wypisze w konsoli ‘napis’

Na razie kod wydaje się podobny, ale prawdziwa siła async/await zawiera się w wielokrotnych zapytaniach. Zacznijmy od prostego wywołania paru funkcji:

const funkcjaZPromisem = () => {
  return new Promise(resolve => {
    setTimeout(() => resolve('napis!’), 1000)
  })
}

const funkcja1 = async () => {
  const zmienna = await funkcjaZPromisem();
  return ‘asynchroniczny ’ + zmienna;
}

const funkcja2 = async() => {
  return ‘jest ’ + await funkcja1;
}

const funkcja3 = async () => {
  return `To ${await funkcja2}`
}

funkcja3().then( res => {
  console.log(res);
});

Powyższe funkcje zwrócą “To jest asynchroniczny napis”. Prawda, że fajne? Tak samo możemy łączyć np. pobieranie danych z jednego serwisu i po ich otrzymaniu zapytać inny serwis o ID z odpowiedzi. Nie musimy jednak wywoływać i tworzyć paru funkcji, taki przykład również zadziała:

const funkcja = async () => {
  const zmienna1= await pierwszaFunkcjaAsync();
  const zmienna2 = await kolejnaFunkcjaAsync(zmienna1[0]);
  const wynik = await finalnaFunkcjaAsync(zmienna2.id);
  return wynik;
}

Podsumowanie

Jak widzisz, zapytania asynchroniczne stają się super proste. Oczywiście, skoro są to promisy, to mają też trochę swoich problemów, ale jednak uproszczenie i ujednolicenie składni dzięki async/await daje nam naprawdę wiele: czytelniejszy kod, szybsza praca, prostsze debugowanie. Polecam używanie async/await z całego serca.

A czy ty używasz async/await? Proszę, daj znać w komentarzu, chętnie wysłucham historii z tym związanych :)