1 2 3 4 5 6 7 8 9 10 11 12 13 |
const test = async () => { await new Promise((resolve)=>setTimeout(() => { console.log("timeout"); resolve(); }, 2000)); console.log(1); console.log(2); } test(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const test = async () => { await new Promise((resolve)=>setTimeout(() => { console.log("timeout"); resolve(); }, 2000)); console.log(1); console.log(2); } test(); |
JavaScript Promise kullanımı;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<script> "use strict"; let sonuc = false; let islem = new Promise(function(resolve, reject) { if (sonuc) { resolve("Başarılı işlem"); } else { reject("Başarısız işlem"); } }); islem .then(function(data) { console.log(data); }) .catch(function(data) { console.log(data); }); </script> |
Promise Sözdizimi
Zincir diyerek kastettiğim şu: biri diğerini bekleyen asenkron işlemlerin arka arkaya çalıştırılması.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const sozVerdik = new Promise(function(resolve, reject){ if (herseyYolunda) { resolve('İşlem tamam!'); } else { reject('Bir sıkıntı var...'); } }) sozVerdik.then(function(cevap){ console.log(cevap) // 'İşlem tamam!' yazısını basar }).catch(function(hata){ console.log(hata) // 'Bir sıkıntı var...' yazısını basar }) |
Promise yapısı gereği asenkrondur ve uygulamadaki bekleyen diğer kodların çalışmasını bekletmez. Bu yüzden sıralı asenkron işlemlerin birbirini beklemesi için promise zinciri diyebileceğimiz yapılar oluşturmamız gerekir.
1 2 3 4 5 6 7 8 9 10 |
asenkronIslem() .then(sonuc => { return baskaAsenkronIslem(sonuc); }) .then(zincirSonuc => { return zincirSonuc.json(); }) .catch(hata => { console.log(hata); }); |
Yukarıdaki kod parçacığı üzerinden promise zincilerine bir bakalım:
Birden fazla .then() arka arkaya eklenerek oluşturulur.
Zinciri başlatan bir promise olduğu gibi .then() içindeki fonksiyonların dönüş değeri de promise olur. return değeri promise’leştirilerek zincirin diğer halkasına aktarılır. Bu yüzden zincirin her bir halkasını promise okuyan ve promise çıktısı oluşturan bir yapı olarak düşünebiliriz.
Hataların yakalanması için tek bir .catch() yeterlidir. Zincir içerisinde ne zaman başarısız (rejected) bir promise veya beklenmedik bir hata oluşursa, sonrasındaki .then() halkaları atlanılarak .catch() içerisindeki fonksiyon çalışır. asenkronIslem, baskaAsenkronIslem, birinci veya ikinci .then()’in hatalı sonuçlanması konsola hata mesajının basılması ile sonuçlanır.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
function ayetSesle(xSira){ // console.log("TIKLANAN "+xSira) secilenSes=""; secilenSes=[]; devamDurum=false; music.remove(); ///// if (isMobile==null) { document.getElementById("desktopDiv").style.display = "block"; document.getElementById("sagBas").innerHTML ='<div class="audDiv"><audio id="player1" controls controlsList="nodownload" class="aud"><source src="" type="audio/mpeg"></audio></div>'; // document.getElementById("sagBas").innerHTML ='<div class="audDiv"><audio id="player1'+sayfaNo+'" controls controlsList="nodownload" class="aud"><source src="" type="audio/mpeg"></audio></div>'; music = document.getElementById("player1"); } else { document.getElementById("mobilDiv").style.display = "block"; document.getElementById("sagBasMobil").innerHTML ='<div class="audDiv"><audio id="player2" controls controlsList="nodownload" class="aud"><source src="" type="audio/mpeg"></audio></div>'; music = document.getElementById("player2"); } ////// for(var md=0; md<ayetDiz.length; md++){ document.getElementById(ayetDiz[md]).style.backgroundColor="white" document.getElementById(ayetDiz[md]).style.color="black" } for (var i=(xSira); i<sesDiz.length ; i++) { secilenSes.push(sesDiz[i]); //console.log(i+"-"+sesDiz[i].ayetYol) } xs=0; music.src="Ghamidi_MP3_Ayet/"+secilenSes[0].ayetYol; // ilk satır renklenmedi document.getElementById(ayetDiz[xSira]).style.backgroundColor="lightblue"; document.getElementById(ayetDiz[xSira]).style.color="red"; //oku(); music.addEventListener("ended", function(){ for(var md=0; md<ayetDiz.length; md++){ document.getElementById(ayetDiz[md]).style.backgroundColor="white" document.getElementById(ayetDiz[md]).style.color="black" } xs++; if(secilenSes.length==xs){ //console.log("sayfa sonu"); devamDurum=true; ileri(); } else { document.getElementById(ayetDiz[xs+xSira]).style.backgroundColor="lightblue"; document.getElementById(ayetDiz[xs+xSira]).style.color="red"; } music.src="Ghamidi_MP3_Ayet/"+secilenSes[xs].ayetYol; //console.log("OKU " + "Ghamidi_MP3_Ayet/" + secilenSes[xs].ayetYol); music.play(); //console.log("A"); // callback() }) } |
Node Js ile json dosyasından okuyarak mysql dosyasına toplu kayıt işlemleri.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
app.get(yol+'/update',function(req,res){ res.render('./updateKelime'); }); app.post(yol+'/guncelle',function(req,res){ //VERİLERİ YÜKLE var tumu fs.readFile('words.json', (err, json) => { if (err) { res.send("Dosya Okunamadı") }else{ tumu = JSON.parse(json); for (var k = 16000; k < tumu.length; k++) //for (var k = 0; k < 10; k++) { var sql = 'UPDATE kelime1 SET ArapcaOz =? WHERE id =' + (k+1); var query = con.query(sql, [tumu[k].text], function (err, result) { if (!err) { // console.log("KAYIT GÜNCELLENDİ!!"); // console.log(k +" "+tumu[k].text) } }) } } }); res.send('işlem tamamdır inşallah'); }); |
Synchronous programlamada işlemler sırayla gerçekleşir. Başka bir deyişle bir işlem bitmeden diğerine geçiş yapılmaz. Aktif olan devam ederken sıradaki işlem bloklanır.
1 2 3 4 5 6 |
console.log("Hello,"); const syncExample = () => { console.log("How are you?"); }; syncExample(); console.log("World."); |
Bildiğiniz gibi Javascript bir single-threaded programlama dilidir. Yani kodu satır satır okur ve sırayla işleme sokar. Bu nedenle yukarıda verilen örneğin outputu şu şekildedir.
1 2 3 |
Hello, How are you? World. |
Asynchronous Programlama Nedir?
1 2 3 4 5 6 7 8 9 |
console.log("Hello,"); const asyncExample = () => { setTimeout(() => { console.log("How are you?"); }, 3000); }; asyncExample(); console.log("World."); |
1 2 3 |
Hello, World. How are you? |
Callbacks, Promise ve Async-Await
Bir örnek üzerinden bu yöntemleri, aralarındaki farkları ve kullanım kolaylıklarını inceleyelim.
1 2 3 4 5 |
function printString(string) { setTimeout(() => { console.log(string); }, Math.floor(Math.random() * 100) + 1); } |
Diyelimki random zamana bağlı olarak string yazdıran bir fonksiyonumuz var.
Bu fonksiyonu kullanarak A, B, C harflerini sırayla yazdıralım.
1 2 3 4 5 6 |
function printAll() { printString("A"); printString("B"); printString("C"); } printAll(); |
Her ne kadar sırayla çağırılmış olsalar da printAll fonksiyonu her çağırıldığında A, B, C harfeleri farklı sırayla loglanır. Daha önceden de açıkladığım gibi printString fonksiyonu asynchronous çalışır. A, B, C için her fonksiyon sırayla çalıştırılır ancak setTimeOut fonksiyonundan dolayı farklı zamanlarda gercekleşirler. Bu da A, B, C harflerinin farklı sırayla loglanmasına sebep olur.
Peki bir fonsiyonu art arda kullanmak istiyorsak ve sırayla gercekleşmesini bekliyorsak ne yapmalıyız? Bu sorunun cevabına geçmeden önce de buna neden ihtiyaç duyduğumuzu da belirtmek istiyorum.
Bu tarz işlemlere bir yere istek atarken ve o istekten dönen cevaplara göre kodun devamını getiriyorsak ihtiyaç duyabiliriz. Çünkü kodu sırayla yazsak bile istek atan fonksiyon satırı okunup isteğin cevabına göre işlemi gerçekleştirecek olan fonksiyon satırına geçildiğinde eğer istek bir cevap dönmediyse undefined hatası ile karşılaşırız. Bu hata ile karşılaşmak istemiyorsak da Promise in resolve olduğu yere istekten gelen cevap ile işlem yapan fonksiyonu çağırabiliriz. Aynı zamanda bu isteğin dönmesini beklerken çalışan kodun bulunduğu satırdan sonrası için çalışmayı durdurur. Bu tarz hataların önüne geçebilmek için de calbackler,promiseler ve async-await kullanılır.
Callbacks
Callback fonksiyonları bağımsız bir değişken olarak başka bir fonksiyona geçirilen ve ilk fonksiyonun işlemi tamamlandıktan sonra diger fonksiyonun işlevini başlatan fonksiyonlardır. Callbackler genellikle asynchronous işlemler tamamlandıktan sonra kod yürütülmesine devam etmek için kullanılır.
Gelin bir örnekle duruma göz atalım.
1 2 3 4 5 6 |
function addString(previous, current, callback){ setTimeout(() => { callback((previous + ' ' + current)) },Math.floor(Math.random() * 100) + 1 ) } |
Şimdi de addAll fonksiyonunu kullanarak A,B, C harflerini yazdıralım.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function addAll(){ addString('', 'A', result => { addString(result, 'B', result => { addString(result, 'C', result => { console.log(result) }) }) }) } addAll() //Output: A B C |
Gördüğünüz gibi bu sefer A,B, C harflerini sırayla yazdırmayı başardık lakin kodumuz oldukça karışık gözüküyor. Zaten callbakleri nerede ve ne zaman kullanacağımıza bu nedenle özen göstermeliyiz. Çünkü fonksiyon içinde fonksiyonları kullanmaya başladıkça kodu okumak gittikçe zorlaşacak ve zamanla “Callback Hell” adı verilen problem ortaya çıkacak. Ayrıca Callbacklerin sebep olduğu bazı hatalar da vardır. Bu hatalardan bazıları şunlardır;
Peki bu hataları yaşamamak için ve işlevlerimi yerine getirmek için hangi yolu izlemeliyiz? Bu sorunun cevabı için gelin beraber bir de promiselere göz atalım.
Promiseler benim gibi Javascript’e yeni başlayan yazılımcılar için büyük ihtimalle en çekimser yaklaşılan konulardan biridir. Peki nedir bu promiseler?
Promiseler, ‘Callback Hell’ durumundan kaçınmak için ve beklenmeyen durumla karşılaşıldığında hata kontrolünün daha rahat yapılabilmesi için geliştirilmiş ES6 olarak bilinen ECMAScript 2015 ile bize sunulan asynchronous bir yapıdır.
Bir promise 3 durumdan oluşur;
Şimdi gelin beraber addString fonksiyonumuzu promise kullanarak yazalım.
1 2 3 4 5 6 7 |
function addString(previous, current) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(previous + " " + current); }, Math.floor(Math.random() * 100) + 1); }); } |
Gördüğünüz gibi callback kullanmak yerine tüm fonksiyonu bir promise içerisine koyduk. Bu promise sonucunda fonksiyonumuz ya resolve olacak ya da reject. Ayrıca promiselerde eğer işlem başarılı olursa then( ), başarısız olursa ve hata durumu olursa catch( ) fonksiyonlarının içine girer. Bu yapıya ise “Promise Chain” denir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function addAll() { addString("", "A") .then((result) => { return addString(result, "B"); }) .then((result) => { return addString(result, "C"); }) .then((result) => { console.log(result); }) .catch((error) => console.log(error)); } addAll(); //Output: A B C |
Gördüğünüz gibi A,B, C harflerini sırayla yazdırmayı başardık. Kod yapısına baktığımızda ise ilk fonksiyonun diğer fonksiyonun sonucunu return ettiğini ve sonucun bir sonraki fonsiyona gönderildiğini görürüz.
Diğer kısma geçmeden önce promise yapısı ile ilgili promise.all( ) ve promise.race( ), promise.allSettled( ) ve promise.any( ) özelliklerinden de bahsetmek istiyorum.
Async/Await yapısı asynchronous işlemleri daha anlaşılması kolay bir hale getiren ECMAScript 2017 ile kullanıma sunulan promise tabanlı bir Javascript özelliğidir.
Anlaşılması kolay derken neyden bahsettiğimi açıklayayım. Şöyle ki biz geliştiriciler olarak, çoğunlukla synchrounous kod yazmaya alışkınız, yani birbiri ardına komut dizileri yazarız. Çünkü bu tarz yazım şeklinin okunması ve anlaşılması çok daha kolaydır. Callbackler ve promiseler döngüsellikleri nedeniyle bizi bu açıdan biraz yorar. Async-await tam olarak o anda yardımımıza koşar.
Şimdi yeniden addString ve addAll() fonksiyonumuza bakalım.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function addString(previous, current) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(previous + " " + current); }, Math.floor(Math.random() * 100) + 1); }); } async function addAll() { let toPrint = await addString("", "A"); toPrint = await addString(toPrint, "B"); toPrint = await addString(toPrint, "C"); console.log(toPrint); } addAll(); //Output: A B C |
Gördüğünüz gibi A,B ve C harflerini sırayla yazdırmayı başardık.
Ayrıca addAll() fonksiyonu içinde geçen ’’async” sözcüğü JavaScript’in async / await sözdizimini kullandığımızı bilmesini sağlar ve Await kullanmak istiyorsanız bu sözcüğü kullanmanız şarttır. Aksi taktirde hata alırsınız.
Async-Await özelliği istek atarken ve o istekten dönen cevaplara göre işlem yapıyorsak sık kullanılan bir yapıdır. Bu nedenle konuyu da daha iyi anlamamız için son bir örnek daha vermek istiyorum.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
async function sendRequest(id, prev = "") { const response = await fetch( `https://604b3120ee7cb900176a185c.mockapi.io/words/${id}` ); const jsonResponse = await response.json(); console.log(jsonResponse); return prev + " " + jsonResponse.value; } async function getAll() { const response1 = await sendRequest(1); const response2 = await sendRequest(2, response1); const response3 = await sendRequest(3, response2); console.log("getAll :>>", response3); } getAll(); |
Client için kodlar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script><style>button{font-size:22px}</style> <h1>BİSMİLLAH</h1> <hr> <div class="container"> <div class="row"> <div class="col-*-*"> <label for="fname">First name:</label> <input type="text" id="adi" name="fname"><br> <label for="lname">Last name:</label> <input type="text" id="soyadi" name="lname"><br> <button onclick="kaydet()">KAYDET</button> </div> <div class="col-*-* pl-3"> <button onclick="ekle()">EKLE</button> </div> <div class="col-*-* pl-3"> <div id="liste"> </div> </div> </div> </div> <script> var yollar = "/kuran" var toplu; var ilave; //VERİLERİ YÜKLE fetch("ogrenciler.json") .then(res => res.json()) .then(jsons => { toplu = jsons; for(i = 0; i < jsons.length; i++) { $("#liste" ).append(i +" - " + jsons[i].ad +" " +jsons[i].soyad +" <br>") } }); function ekle(){ document.getElementById("liste").innerHTML = ""; ilave = { ad: document.getElementById("adi").value, soyad:document.getElementById("soyadi").value } fetch("ogrenciler.json") .then(res => res.json()) .then(jsons => { toplu = jsons; toplu.push(ilave); for(i = 0; i < toplu.length; i++) { $("#liste" ).append(i +" - " + toplu[i].ad +" " +toplu[i].soyad +" <br>") } }); } function kaydet(){ fetch(yollar+'/json', { method: "post", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(toplu) }) } </script> |
Node Js server bölümünde de dosya kayıt ediliyor.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
app.get(yol+'/json',function(req,res){ res.render('./json'); }); app.post(yol+'/json',function(req,res){ var gelen = req.body; /* const dir = './jdata'; if (!fs.existsSync(dir)){ fs.mkdirSync(dir); } */ fs.writeFile('public/ogrenciler.json', JSON.stringify(gelen), 'utf8', (err)=>{ if(err){ res.send("Dosya oluşturulurken Bir hata gerçekleşti") }else{ res.send("Dosya Başarıyla Oluşturuldu") } }); res.json("gelen.ad"); }); |
Javascript’in Asenkron özelliğinin önüne geçmek için callback fonksiyonu kullanılır.
Öncelikle hatırlayalım callback neydi diye. Callback, en basit haliyle herhangi bir fonksiyona parametre olarak verdiğimiz ve sonra geri çağıracağımız fonksiyonlara denir. İstenilen değere ulaştığında veya işlem sonlandığında görevini yerine getirir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function first(callback) { setTimeout( function () { alert(1); callback() }, 500); } function second() { alert(2); } first(second); // çıktı // 1 // 2 |
1 2 3 4 5 6 7 8 9 10 11 |
function yaz(limon) { console.log("BURASI BİTMEDEN CALLBACK ÇALIŞMAZ") limon() } function kalem(){ console.log("BURASI SONRADAN DEVREYE GİRER") } yaz(kalem); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<!DOCTYPE html> <html> <body> <h2>JavaScript Callbacks</h2> <p>Do a calculation and then display the result.</p> <p id="demo"></p> <script> function myDisplayer(something) { document.getElementById("demo").innerHTML = something; } function myCalculator(num1, num2, myCallback) { let sum = num1 + num2; myCallback(sum); } myCalculator(5, 5, myDisplayer); </script> </body> </html> SONUÇ OLARAK JavaScript Callbacks Do a calculation and then display the result. 10 |
Merhaba,
Yazılım dendimi akıllara kompleks ve anlamsız işlemlerden anlamlı sonuçlar üreten bir olgu gelmektedir. Bu kompleks süreçler, son kullanıcılara mümkün mertebe yansıtılmadan programın hizmet edeceği iş ne ise o alana dönük olabildiğince tüm işlemler arayüz odaklı halledilebilir hale getirilmektedir. Tabi süreci sadece son kullanıcı odaklı düşünürsek ilgili yazılımda nihai erişimi arayüzsel seviyede yönetilebilir hale getirmek yeterli olacaktır. Lakin bu işin bir de yazılım geliştiricileri boyutu mevcuttur. Yani kompleks sürecin tam merkezinde yani işin kod ve veri kısmında bulunan yazılım ekibi bu süreci kendi lehlerinde anlamlandırabilirlerse, hem geliştiriciler için hem de yazılımın geleceğe dair gelişimindeki eğilimi için oldukça faydalı katkıda bulunulmuş olacaktır.
Aslında bu anlamlandırma uğraşısı, yazılımın sağlam temellerde inşa edilmesini sağlayacağından dolayı doğru, prensipli ve anlaşılabilir kod inşaasını gerektirecek ve bir yandan da yazılımcılar için projeye hiyerarşik boyut kazandıracak neyin, nerede ve ne amaçla olduğuna dair daha geniş perspektifle ilgili projeye bakış açılarını genişletecek ve verimi arttıracaktır. Yani yazılım geliştiriciler ustaysa eğer inşaatta çekicin çivinin nerede nasıl tutulduğunu bilmeleri işlerinde hızlanmalarını sağlayacaktır.
Teknik boyutta bir projeyi daha anlamlı hale getirmek için öncelikle doğru yaklaşımlarla ilgili proje tasarlanmalıdır. Buda doğru ve detaylı plan gerektirmektedir. Tasarıya dönük olması gerektiği yerlerde ise bir Çinli ile bir başka Aborjin yazılım geliştiricinin birbirlerinin beşeri dillerini bilmeden, birinin yaptığı işi bir diğerinin tek bakışta ve tek seferde anlayabilmesini sağlayacak olan design pattern(tasarım desenleri) yapıları uygulanmalıdır. Tüm bunların yanında proje mümkün mertebe katmansal hale getirilmeli ve tekrardan dünya standartlarında bir katmanlı mimarinin eşliğinde proje temellendirilip ihtiyaca dönük özel katmanlarla genişletilmelidir.
Bu içeriğimizde bizler bir projenin katmansal hale getirilmesini Node.js’in Express.js modülünde küçük bir noktada değerlendirecek ve gelen requestlere karşılık response gönderilmeden araya Middleware şeklinde isimlendirilen ara katman sokacağız. Şimdi gelin Middleware’in ne işe yaradığını ve nasıl kullanıldığını inceleyelim.
Klasik web uygulamalarında, kullanıcıdan gelen taleplere(request) karşılık cevaplar(response) gönderilmektedir.
Gelişmiş yapılanmada ise, request – response işlevsel ilişkisinin arasına Middleware girebilmekte ve tek elden ek işlemler icra edilebilmektedir.
Middleware katmanı, genellikle tüm route rotalarında yapılacak işlemleri tek elden yönetmek için kullanılmaktadır. Genellikle bu işlemlerden biri kullanıcı oturum kontrolüdür. Her bir route üzerinde bu kontrolü yapmanın ne kadar maliyetli ve lüzumsuz kod israfına yol açacağını siz düşünün…
Şimdi Middleware ile ilgili teknik boyutta değerlendirmelere başlayalım.
01020304050607080910 | const express = require( "express" ); const app = express(); app.use((request, response, next) => { response.send( "Middleware çalıştı." ); }); app.get( "/" , (request, response) => { response.send( "Route çalıştı..." ); }).listen(5000); |
Yukarıdaki kod bloğunu incelerseniz eğer “app.use” fonksiyonu içerisine tanımlanan callback fonksiyonu ile Middleware’i oluşturmuş oluyoruz. Bu işlemden sonra “app” üzerinden oluşturulan tüm route yapıları için herhangi bir istek söz konusu olursa bu istek karşılığında cevap verilmeden önce ilgili middleware devreye girecektir.
“Tamam, istek neticesinde ilgili middleware devreye girdi girmesine ama sanki tetiklenen route çalıştırılmadı la hoca!” diye söyleniyor olabilirsiniz… Evet, haklısınız. Ama bu sorunuzun cevabına gelmeden önce middleware fonksiyonumuzdaki parametrelerden en sonuncusu olan “next” fonksiyonunu inceleyelim.
“next” parametresi yukarıda bahsettiğim gibi bir fonksiyondur. Bu fonksiyon çağrıldığı zaman ilgili middleware’de ki çalışmaların onaylandığı bir başka deyişle doğrulandığı söz konusu olacaktır ve middleware tetiklenmeden önce hangi route’a istek gönderildiyse o route bu doğrulama neticesinde çalıştırılacaktır.
Bu mantıkla yukarıdaki çalışmaya göz atarsak eğer “next” fonksiyonu çağrılmadığı için ilgili tetiklenen route çalıştırılmamıştır.
01020304050607080910 | const express = require( "express" ); const app = express(); app.use((request, response, next) => { next(); }); app.get( "/" , (request, response) => { response.send( "Route çalıştı..." ); }).listen(5000); |
Bu şekilde “next” fonksiyonunu tetiklersek direkt olarak route tetiklenecektir.
Şimdi örneğimizi daha da derinleştirerek konumuzu detaylandırmak için bir kullanıcı oturum kontrolü sağlayalım.
010203040506070809101112131415161718 | const express = require( "express" ); const app = express(); app.use((request, response, next) => { let isLogin = false ; if (isLogin) next(); else response.send( }); app.get( "/" , (request, response) => { response.send( "Anasayfa" ); }).get( "/profil" , (request, response) => { response.send( "Profil sayfası." ); }).get( "/ayarlar" , (request, response) => { response.send( "Ayarlar sayfası." ); }).listen(5000, () => console.log( "Yayın başladı..." )); |
Yukarıdaki kod bloğunu incelerseniz eğer “/”, “/profil” ve “/ayarlar” adreslerine olmak üzere üç adet route oluşturulmuştur. Bu routelara yapılan isteklerde middleware devreye girecek ve kullanıcı oturum kontrolü yapacaktır. Eğer oturumu açıksa ilgili sayfalara yönlendirecektir.
Gördüğünüz gibi biz manuel olarak oturumu false değerinde tuttuğumuz için hiçbir route’a erişim gerçekleştirilememektedir.
Eğer ki bir middleware katmanının sade ve sadece istediğiniz bir route rotasında uygulanmasını istiyorsanız aşağıdaki gibi çalışma gerçekleştirebilirsiniz.
01020304050607080910111213 | . . . app.use( "/profil" , (request, response, next) => { let isLogin = false ; if (isLogin) next(); else response.send( }); . . . |
“use” fonksiyonunun ilk parametresine hangi routeta middleware’ın çalışılmasını istiyorsanız belirtmeniz yeterlidir.
Middleware katmanını farklı bir modül olarak tasarlayarak ihtiyaca dönük gereken noktalarda require edebilir ve kullanabiliriz.
123456789 | //-isLogin.js const isLogin = (request, response, next) => { let isLogin = false ; if (isLogin) next(); else response.send( }; module.exports = isLogin; |
Yukarıda görüldüğü üzere modül olarak tasarlanan middleware katmanını aşağıdaki gibi require ederek kullanabiliriz.
123456789 | . . . const isLogin = require( "./isLogin" ); app.use(isLogin); . . . |
Export edilen modülü require ile elde ettikten sonra “app.use” fonksiyonuna direkt olarak vermemiz yeterlidir.
Modül bazlı çalışırken istenilen route rotasında middleware katmanını kullanmak isterseniz eğer aşağıdaki gibi çalışabilirsiniz.
010203040506070809101112 | const express = require( "express" ); const app = express(); const isLogin = require( "./isLogin" ); app.get( "/" , isLogin, (request, response) => { response.send( "Anasayfa" ); }).get( "/profil" , (request, response) => { response.send( "Profil sayfası." ); }).get( "/ayarlar" , isLogin, (request, response) => { response.send( "Ayarlar sayfası." ); }).listen(5000, () => console.log( "Yayın başladı..." )); |
Görüldüğü üzere direkt olarak route fonksiyonlarında ikinci parametre olarak ilgili middleware modülünü vermemiz yeterlidir.
Eğer ki middleware modülleri birden fazla ise aşağıdaki gibi bir yaklaşım sergileyebilirsiniz.
01020304050607080910111213 | . . . const app = express(); const isLogin = require( "./isLogin" ); const control = require( "./control" ); app.get( "/" , isLogin, control, (request, response) => { response.send( "Anasayfa" ); }) . . . |
Dikkat ederseniz eğer route rotasında ilk parametreden sonra istenildiği kadar middleware atanabilmektedir. Buradaki öncelik sıralaması atama sıralamasıyla birebir uyumludur. Yani ilk olarak “isLogin” middleware katmanı kontrol edilecek. Eğer “next” metodu tetiklenirse ardından “control” middleware katmanı denetlenecektir. Ve bu işlem atanan n adet katman için bu şekilde devam edecektir.
Bir yazımızın daha sonuna gelmiş bulunmaktayız. Umarım bol bol faydalanırsınız.
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar dilerim…