Yeni bir sıfırdan ileriye Javascript konusuna hoş geldiniz. Bugünkü konumuz Promisesler. Promisesler, JavaScript'te asenkron işlemleri işlemenin bir yoludur. Asenkron bir eylemin nihai başarı değeri veya başarısızlık nedeni olan işleyicilere izin verir. Bu, asenkron yöntemlerin senkron yöntemler gibi değerler döndürmesini sağlar: son değeri hemen döndürmek yerine, asenkron yöntem gelecekte bir noktada değeri sağlamak için bir söz döndürür. Belli bir süre içinde bizlere beklemede, reddedildi,tamamlandı gibi değerler dönecektir.
Normalde Javascript senkronize bir şekilde çalışır yani kodlar yukarıdan aşağıya doğru çalışır ama bazen önce aşağıdaki kod çalışsın sonra yukarıdaki kod gibi birtakım durumlar olabilir bu durumlarda asenkron dediğimiz yapı dahil olur. Burada asenkron olacak olan yerleri belirterek öncelik sırasını ona veririz. Böylece daha stabil bir program ortaya çıkacaktır.
Callback ve Callback Cehennemi
Promoisesler, başta anlaşılması zor bir konudur. Bu yüzden en temelden alarak callbackleri öğrenelim. Bunun sebebi ise promoiseslerden önce Javascripte callbackler kullanılıyordu ve bu callbackler zaman zaman kodun okunmasını zorlaştırıyordu buna callback hell de denilmiştir. Önce callbacklerin yapısını daha sonra callback hell'i görelim.
JavaScript:
const fonksiyon = callback => {
setTimeout(() => {
const yetenekler = ['HTML', 'CSS', 'JS']
callback('Benim bildiğim teknolojiler HTML,CSS;Javascripttir', yetenekler)
}, 2000)
}
const callback = (err, sonuc) => {
if (err) {
return console.log(err)
}
return console.log(sonuc)
}
fonksiyon(callback)
İlk olarak ok fonksiyonu kullanarak bir callback tanımladık isterseniz buna kendi adınızı da koyabilirsiniz ama pek hoş durmaz. Daha sonra setTimeout'un içine yetenekler dizisi ve tanımladığımız callbackin içeriğini yazdık. SetTimeout ile birlikte sayfa açıldıktan 2000 milisaniye (2 saniye) sonra bu içeriklerin bize gelmesini istedik. Daha sonra bir adet callback fonksiyonu tanımladık ve bunun için err ( error) ve sonuç değişkenleri atadık. Bu kişiye bağlı değişken adlarıdır. Eğer err çalışırsa err değerini konsola dön eğer err değeri olmazsa yani sorun oluşmazsa bize sonuç değişkeninin içeriğini dön dedik. En sonda da fonksiyonumuzun içine callback metodunu atayarak fonksiyonu çalıştırdık.
Err değeri false olacağı için görmek callback'İn çıktılarını aldık. Bu sefer callback'i false yapalım.
JavaScript:
const fonksiyon = callback => {
setTimeout(() => {
const yetenekler = ['HTML', 'CSS', 'JS']
callback(false, yetenekler)
}, 2000)
}
const callback = (err, sonuc) => {
if (err) {
return console.log(err)
}
return console.log(sonuc)
}
fonksiyon(callback)
False değer yani error değeri döneceği için dizi elemanlarını çıktıda gördük. Temelde callback budur. Gayet güzel hoş gözüküyor neden callback değil de promieses kullanmamız gerekiyor sorusuna ise callback hell sorunu karşımıza geliyor. Temelde kodun okunmasını çok zorlaştıran bir yapıdır callback hell. Haydi bir tane cehennemi de biz yapalım.
JavaScript:
const fonksiyon = (callback) => {
setTimeout(() => {
const yetenekler = ['HTML', 'CSS', 'JS'];
callback(null, `Benim bildiğim teknolojiler: ${yetenekler.join(', ')}`);
}, 2000);
};
const callbackHell = () => {
fonksiyon((err, sonuc) => {
if (err) {
return console.log(err);
}
console.log(sonuc);
setTimeout(() => {
const diller = ['Python', 'Java', 'C#'];
console.log(`Benim bildiğim programlama dilleri: ${diller.join(', ')}`);
setTimeout(() => {
const frameworkler = ['React', 'Angular', 'Vue'];
console.log(`Benim bildiğim frameworkler: ${frameworkler.join(', ')}`);
setTimeout(() => {
const veritabanlari = ['MySQL', 'MongoDB'];
console.log(`Benim bildiğim veritabanları: ${veritabanlari.join(', ')}`);
}, 2000);
}, 3000);
}, 4000);
});
};
callbackHell();
Direkt kodu okumaya çalışmak bile göz yoruyor. Bir adet callback fonksiyonu oluşturup içine callback tanımladık daha sonra eğer err değeri dönerse err değerini return et eğer değilse sonucu dön dedik. Klasik callbackimiz hazır. Daha sonra setTimeout ile diller dizisini konsola yazdırma işlemini yaptık bu ilk diziyi yazdırma işlemi 2 saniye sürecektir. Daha sonra bir setTimeout ile bu sefer freamworkler dizsini yazdırmaya kalktık ve bu freamwork, ilk diziden 1 saniye sonra yani sayfa açıldıktan sonra 3 saniye sonra konsola düşsün dedik. Bir setTimeout ile daha bu sefer veritabanları dizisini yaz ve bu da 4 saniye sonra gelsin derken okunamaz, hantal, yazılması karışık ve zor bir kod parçacağı elimize geldi. Bunu yaşamamak için promoisesleri kullanacağız.
Promoisesler
Promoisesleri oluşturmak için bir değişkene new Promoise kodunu yazarız ve bunun içine 2 adet değer (olumlu ve olumsuz sonuçlar için) girilir. Daha sonra promise yapısı tanımlandıktan sonra .then ve .catch kodlarıyla çalıştırılır.
JavaScript:
const sozler = new Promise((cozum, reddet) => {
setTimeout(() => {
const yetenekler = ['HTML', 'CSS', 'JS']
if (yetenekler.includes('Node')) {
cozum('fullstack developer')
} else {
reddet('Bir şeyler yanlış gitti')
}
}, 2000)
})
sozler
.then(sonuc => {
console.log(sonuc)
})
.catch(error => console.error(error))
İlk olarak burada sözler diye bir metod oluşturduk ve bu metoda new Promise ve içindeki iki değer (değişken adları size kalmış) tanımlayarak fonksiyonumuzun içine geldik. SetTimeout ile sayfa açıldıktan 2 saniye sonra çalışmasını istedik. Bu çalışacak değerleri de setTimeout'un içine tanımladık. Yetenekler dizisini tanımladıktan sonra if bloğu ile eğer yetenekler dizisi Node stringini içeriyorsa cozum değişkenine full stack develepor stringini ata ama eğer Node, dizinin içine yoksa konsola hata mesajını yazdır diyoruz. Promisesi oluşturduktan sonra bunu çağırıyoruz. Önce metod adını sonra .then ile bize olumlu sonucu dönmesini eğer durum false ise .catch ile de error mesajını bize dönmesini istiyoruz.
Sozler metodu içinde Node olmadığı için error değeri dönecektir. Eğer dizi içine Node eklersek bu sefer fullstack developor değeri dönecektir.
Bunun en büyük faydalarından biri de hayal edin bir kullanıcı web sitenin ödeme kısmında hata aldı. Javascript normal errorlarını kullanıcıya gösterirsek hali ile anlamayacaktır. Yok sytnax error, yok xxx function is not defined vs vs. Bir nevi oluşacak hataları kullanıcıların diline de çevirmiş oluruz.
API Kullanımı
Front-end denilince iş html css işte biraz da Javascriptle butonlara özellik eklemeden ibaret değil. Back-end geliştiricilerin oluşturduğu API'leri de sisteme uygun şekilde aktarmalıdır bir front-endci.
API kısaca sunucudaki veriler (veritabanı vs.) ile web site arasındaki oluşumdur diyebiliriz. Mesela bir hava durumu projesi yapacaksınız bunu nasıl yapardınız ?
Tek tek tüm ülkeri, bu ülkelerin şehirlerini vs yazmaya kalksak geçmiş olsun. Bunu back-endciler bir şekil json formatın dönştürüp bizlere getiriyor. Bizim de bunları kullanıcını kullanabileceği ve görebileceği şekilde ayarlamak kalıyor.
Benim tecrübe ettiğim ve ünlü 3 tane api getirme çeşidi vardır. Bunlar XMLHttpRequest (En ilkeli), Fetch, ve axiostur. Bu konuda sizlere hepsini göstereceğim ama axios biraz da terminal bilgisi istemektedir. Çok fazla değil ama terminale aşina iseniz daha kolay kaparsınız olayı.
İlk olarak bu yöntemleri denemek için bizlere bir api lazım bunu JSONPlaceholder ile yapabiliriz. Siz de denemek istiyorsanız Google JSONPlaceholder yazmanız yeterli olacaktır ilk çıkan sayfaya girip biraz aşağıya kaydırın sayfayı daha sonra Resources kısmını görüceksiniz. Buradan users kısmını en azından ben kullanacağım siz comments de kullanabilirsiniz size kalmış.
XMLHttpRequest ile Api Çekmek
İlk olarak XMLHttpRequest ile veri çekelim.
JavaScript:
let kullaniciAL = new XMLHttpRequest()
kullaniciAL.open("GET", "https://jsonplaceholder.typicode.com/users")
kullaniciAL.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
const kullaniciAdAl = JSON.parse(this.response)
kullaniciAdAl.forEach(kullanici => {
console.log(kullanici.name)
})
}
}
kullaniciAL.send()
İlk olarak kullaniciAl değişkenine yeni bir xml http isteği oluşturma özelliği tanımladım. Bu özelliği tanımladıktan sonra birçok yeni parametre alacak değişkenimiz. değişkenadı.open ile get metodunu kullanıyoruz. Bunun sebebi apideki verileri alıyoruz eğer göndermek isteseydik post kullanacaktık. Get ile api verilerini almak istediğimizi belirttikten sonra api linkini yerleştiriyoruz. Daha sonra değişkenadı.onreadystatechange metodunu bir fonksiyona dönüştürüp bunu içine bir if bloğu açıyoruz. Eğer readyState == 4 yapıyoruz. ReadyState 5 tane durumu vardır. Bunlar :
0 = İstek başlatılmadı
1 = open() metodu çağırıldı istek başarılı
2 = İstek sunucuya gönderildi (send() metodu kullanıldı)
3 = Sunucudan gelen veriler işleniyor
4 = İstek tamamlandı ve veriler alındı.
Ayrıca statusun ise 4 durumu vardır bunlar :
404 = Sayfa bulunamadı
500 = Sunucu Hatası
403 = Yetkisiz işlem
200 = Başarılı işlem
Kısaca bu if bloğu içinde eğer ready state isteği tamamlanıp veriler alındıysa ve sunucudaki işlem başarılı ise kullanıcıAdAl değişkenine aldığımız değerleri json formatından stringe çevir ve bu çevirdiğimiz değerleri forEach ile teker teker konsola yazdır dedik. En sonda ise send metodunu kullanarak aslında sunucuya veri çekmek için istekte bulunduk.
Ne kadar uğraştırıcı bir işlem yok 4 yok 200 bir apideki isimleri daha az kodla çok daha çekebiliriz. Bu yüzden XmlHttpRequest mazide kaldı.
Fetch API
Burada ise then ve catchlar da kullanacağız. Ayrıca fetch ile aldığımız verileri dizi olarak almış oluruz. Dilerseniz dizi içindeki objelere ulaşarak en küçük veriyi de alabiliriz. (Ad, memleket, vs.)
Kod:
fetch(apiAl)
.then(then => then.json())
.then(data => {
console.log(data)
})
.catch(err => console.log(err))
Burada görüldüğü gibi 10 tane kullanıcının hepsini dizi halinde aldık. Ben sadece 10 kişinin ad soyadını istiyorsam bir döngüye sokup data.name kullanacağım.
JavaScript:
const apiAl = ("https://jsonplaceholder.typicode.com/users");
fetch(apiAl)
.then(then => then.json())
.then(data => {
data.forEach(kullaniciAd =>
console.log(kullaniciAd.name)
)
})
.catch(err => console.log(err))
Yukarıdaki koda ek olarak data içinde forEach döngüsü başlatıp bu döngü sayesinde apide bulunan tüm isimleri sıraladım. Şimdi genel olarak toparlarsak :
İlk olarak apiAl ile api linkini aldık. Daha sonra fetch ile api URL'sine sahip olan değişkeni aldık. Then metoduyla json formatından diziye çevirdik. Bir başka then ile verileri yazdırmak için datayı forEach ile dizi döngüsü başlatıp apideki tüm adları alıp konsola yazdırdık. Son olarak da sorun oluşması halinde catch ile error yazdırma yaptık. Bir biraz üsteki XmlHttpRequest'e bakın bir de buna. Ne kadar kısa ve temiz kod.
Axios
Son olarak da Axios'a değinelim ve konuyu bitirelim. Axios için ilk olarak bilgisayarınızda Nodejs inmiş olmalı. Eğer yoksa küçük araştırma ile NodeJS indirebilirsiniz. (Konudan sapmamak adına burayı geçiyorum). Nodejs kurup cmd üzerinden şunu yazın :
Kod:
nodejs --v
Eğer NodeJs indirip başarılı bir şekilde kuruldu ise size hangi sürüm olduğunu gösterecektir. Sürümü gördüyseniz axios'a hazırsınız demektir.
İlk olarak Vscode üst sekmelerinde bulunan terminal kısmına tıklayın > new terminal > hangi dosyada işlem yapacaksanız o dosya adını seçin. Eğer bir dosyada birden fazla klasör varsa mutlaka o klasörün dizinine geçiniz. (cd dosyadı) Dosya dizinine geçtikten sonra veya terminali dosyaya yazdıktan sonra
Kod:
npm install axios
Komutunu girin ve axios dosyalarını indirielim. Axios dosylarını indirikten sonra şimdi api çekelim.
JavaScript:
const axios = require('axios').default;
axios.get("https://jsonplaceholder.typicode.com/users")
.then(response => {
response.data.forEach(user => {
console.log(user.name);
});
})
.catch(error => console.log(error));
Axios yazar yazmaz bize axios kütüphanesini import edecek bir kod gelir. Bu kodu gördükten sonra axios.get (eğer sunucuya gönderiliyorsa post atılır) + api linki daha sonra then ve catch blokları ile yakalarız. then içine bir değişken tanıyıp bunun data verisini döngü ile döndürür ve isimleri konsola sırayla yazdırırız. Catch ile bir sorun durumunda error mesajı yazdırırız.
Bir başka konunun daha sonuna geldik. Bu bölümde zorlandıysanız bu gayet normaldir. Tekte anlanabilecek bir konu değil. Pratik ve tekrar yaparsanız çocuk oyuncağı olacak ve ayrıca sunucudan veri alıp oraya buraya verileri atmak bence çok da eğlenceli. Başka bir konuda görüşmek üzere okuduğunuz için teşekkür ederim