Async Javascript

Async Functions'larla alakalı çektiğim videoya buradan ulaşabilirsiniz.

Javascript single thread çalışan bir dildir. Kendisinin sadece 1 tane call stack'i bulunur. Yani aynı anda sadece tek bir işlem yapar. Peki javascript yalnızca aynı anda tek bir işlem yapıyorsa cevap bekleyen sorgularda (api'dan data beklemek gibi) neden sayfa kilitlenmiyor. Bunun nedeni asenkron fonksiyonlari webApi kısmına iteliyor javascript. WebApi işini hallediyor. Cevap geldiği zaman cevabı alıp event loop sayesinde birlikte call stack boşalinca cevabi call stack'e atıyor. Opps biraz karisik değil mi? Biz bugün asenkron fonksiyonlardan gelen cevaplarla nasıl işlem yapabiliriz ona bakacağız.

Değineceğimiz konular:

  1. Callback Function
  2. Promises
  3. Async/Await

Callback Functions

Daha önce de söylediğimiz gibi parametre olarak yolladığımız her fonksiyona callback function diyoruz. Callback function'a bir ornek verelim.

function introduceHuman() { console.log("I am human"); } function greeting(callbackFn) { console.log("hello"); callbackFn(); } greeting(introduceHuman);

Bu örnekte asenkrona ait hiçbir durum yok. Callback'i sadece asenkron durumlar için kullanmıyoruz. Burada ona değinmek istedim. Peki db'den bir cevap bekleyelim ve gelen cevabi ekrana yazdıralım. Db'den datanın 5 saniye sonra geleceği bir durum oluşturalim. Burada webApi'in sağladığı özel ve async çalışan setTimeout metodunu kullanacağım. 5 saniye sonra bize users dönsün.

const users = [ { name: "ugur", surname: "coskun", type: "admin" }, { name: "emre", surname: "coskun", type: "guest" }, ]; function getUserDataAccordingToType(type) { setTimeout(() => { return users.filter((user) => user.type === type); // API call }, 5000); } const admins = getUserDataAccordingToType("admin"); console.log(admins);

Burada setTimeout bize direk bir değer döndüremeyecektir. 5 saniye durduktan sonra bize değer dönecektir. setTimeout asenkron çalıştığı için çalışan programımızı durdurmayacaktır. webapı'a gönderilecek sonra direk alt satıra geçecektir. Cevap geldiğinde event loop eğer call stack'imiz bossa cevabı call stack'e gönderecektir. Bu noktada call stack ve webapı's konularına çok derin girmeyeceğim. Bu kısımı çok net anlamamış olabilirsiniz. Biz suan için asenkron fonksiyonlardan gelen değerleri nasıl kullanacağımıza değinmek istiyorum.

Yukarıdaki örnekte getUserDataAccordingToType fonksiyonu bize 5 saniye sonra değer döndürecektir. Bu nedenle admins değerimiz suan için undefined ile yazılır. Burada bekledikten sonra admins değerimizi yazdırmak için callback function kullanabiliriz. Hadi yapalım.

const users = [ { name: "ugur", surname: "coskun", type: "admin" }, { name: "emre", surname: "coskun", type: "guest" }, ]; function getUserDataAccordingToType(type, callbackFn) { setTimeout(() => { const admins = users.filter((user) => user.type === type); // API call callbackFn(admins); }, 5000); } getUserDataAccordingToType("admin", (data) => console.log(data));

Yukarıda gördüğünüz gibi callback function tanımladık. Callback function'a parametre olarak admins'i verdik. Böylece 5 saniye sonra admini filtrelendikten sonra çallback fonksiyonumuzu çağıracak ve admini yazdıracak.

Peki birde dönen adminin sahip olduğu postları bulalım.

const users = [ { name: "ugur", surname: "coskun", type: "admin" }, { name: "emre", surname: "coskun", type: "guest" }, ]; const posts = [ { name: "ugur", post: "Post 1" }, { name: "ugur", post: "Post 2" }, { name: "emre", post: "Post 3" }, { name: "emre", post: "Post 4" }, ]; function getUserDataAccordingToType(type, callbackFn) { setTimeout(() => { const admin = users.filter((user) => user.type === type)[0]; // API call callbackFn(admin); }, 5000); } function getPostAccordingToName(user, callbackFn) { setTimeout(() => { const userPosts = posts.filter((post) => post.name === user.name); callbackFn(userPosts); }, 2000); } getUserDataAccordingToType("admin", (admin) => { console.log(admin); getPostAccordingToName(admin, (post) => console.log(post)); });

Şimdi bu postların her birinin likelarını loglayalım..

const users = [ { name: "ugur", surname: "coskun", type: "admin" }, { name: "emre", surname: "coskun", type: "guest" }, ]; const posts = [ { name: "ugur", post: "Post 1" }, { name: "ugur", post: "Post 2" }, { name: "emre", post: "Post 3" }, { name: "emre", post: "Post 4" }, ]; function getUserDataAccordingToType(type, callbackFn) { setTimeout(() => { const admin = users.filter((user) => user.type === type)[0]; // API call callbackFn(admin); }, 2000); } function getPostsAccordingToName(user, callbackFn) { setTimeout(() => { const userPosts = posts.filter((post) => post.name === user.name); callbackFn(userPosts); }, 2000); } function getLikeOfPost(post, callbackFn) { setTimeout(() => { callbackFn(150); }, 2000); } getUserDataAccordingToType("admin", (admin) => { getPostsAccordingToName(admin, (post) => { getLikeOfPost("test", (likes) => console.log(likes)); }); });

Peki gelen like'lara göre yeni bir fonksiyon yazsak. Daha sonra o gelen fonksiyona göre yenisini. Sonra yenisini. İşte buna callback hell diyoruz.

getUserDataAccordingToType("admin", (admin) => { getPostAccordingToName(admin, (post) => { getLikeOfPost("test", (likes) => getLikeOfPost("test", (likes) => getLikeOfPost("test", (likes) => getLikeOfPost("test", (likes) => getLikeOfPost("test", (likes) => getLikeOfPost("test", (likes) => console.log(likes)) ) ) ) ) ); }); });

Okunurluk çok kötü, maintaince'i zor. Bu durumdan kurtulmak için asynç fonksiyonları handle ettiğimiz bir diğer yapıya geçiyoruz. Promise!!

Note: Callback functionlari senkron calisan yapilar icinde kullanabiliriz.

Promises

Javascriptin bize sunduğu (es6 ile gelen) promise'lerle yukarıdaki örneği gerçekleyelim.

const users = [ { name: "ugur", surname: "coskun", type: "admin" }, { name: "emre", surname: "coskun", type: "guest" }, ]; const posts = [ { name: "ugur", post: "Post 1" }, { name: "ugur", post: "Post 2" }, { name: "emre", post: "Post 3" }, { name: "emre", post: "Post 4" }, ]; function getUserDataAccordingToType(type) { return new Promise((resolve, reject) => { setTimeout(() => { const admin = users.filter((user) => user.type === type)[0]; // API call resolve(admin); }, 2000); }); } function getPostsAccordingToName(user) { return new Promise((resolve, reject) => { setTimeout(() => { const userPosts = posts.filter((post) => post.name === user.name); resolve(userPosts); }, 2000); }); } function getLikeOfPost(post) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(150); }, 2000); }); } getUserDataAccordingToType("admin") .then((admin) => getPostsAccordingToName(admin)) .then((posts) => getLikeOfPost(posts)) .then((like) => console.log(like)) .catch((err) => console.log(err));

Yukarıda callback örneğinin promise ile yapılmışı var. Callback hell'den kurtulduk değil mi? Promise içersinde bir callback function döner. Bu fonksiyon resolve ve reject olarak bize iki method verir. Bu methodlar sayesinde promise resolve ve reject ile değer döndürür. Resolve olumlu sonuçlanırsa kullanacağımız metod, reject olumsuz sonuçlanınca kullanacağımız method. Resolve değerlerini then ile alırken, reject değerleri bizi catch bloğuna gönderir. Böylelikle bu değerleri then ve catch metodlarının içinde kullanabiliriz.

async/await

Şimdi bu promise fonksiyonlarını satır satır bekleyerek kullanalım. Benimde en çok kullandığım yöntem bu. Bu yöntemin okunurluğu çok kolay. Aşağıdaki yapıda aynı sonucu alıyoruz.

async function main() { const admin = await getUserDataAccordingToType("admin"); const posts = await getPostAccordingToName(admin); const like = await getLikeOfPost(posts); console.log(like); } main();

Peki promise'lerin herhangi biri reject olursa bu durumu nasıl handle edebilirsin. try ve catch ile : )

async function main() { try { const admin = await getUserDataAccordingToType("admin"); const posts = await getPostAccordingToName(admin); const like = await getLikeOfPost(posts); console.log(like); } catch (err) { console.log(err); } } main();

Hepsi bu kadar : ) Umarim yararlı olmuştur kendine iyi bak : )

Leave A Comment!
There is no comment yet! Be first!