JavaScript’teki kalıplar ve en iyi uygulamalar: geri arama işlevlerini kullanma



  1. JavaScript’teki kalıplar ve en iyi uygulamalar: geri arama işlevlerini kullanma

Diğer tüm programlama dillerinde olduğu gibi, JavaScript’in de bir dizi ilişkili en iyi uygulamaları ve kötü uygulamaları vardır. JavaScript, dinamik yapısı nedeniyle, geliştiricilerin bilmesi gereken çeşitli tuzaklara da sahiptir. Bu yeni makale dizisi her şeyi kapsamayı amaçlıyor: iyi uygulamalar, kötü uygulamalar ve dil özellikleri. Geri arama işlevleri başlar.


Geri arama işlevleri, yani diğer işlevlere parametre olarak iletilen ve diğer işlevlerden çağrılan işlevler, zaman uyumsuz JavaScript geliştirmede yaygın bir tasarım modelidir. Bu tasarım deseninin temel (henüz optimal olmayan) yapısı aşağıdaki gibidir:

function doSomething(callback) {
/* ... */
callback();
/* ... */
}

İşlev bir şey yap() parametre olarak bir işlev bekler ve onu belirli bir zamanda çağırır:

function doSomethingElse() {
console.log('Callback aufgerufen');
}
doSomething(doSomethingElse); // Ausgabe: "Callback aufgerufen"
Geri arama işlevinin türünü kontrol eder


JavaScript’in zayıf yazımından dolayı, parametre olarak bir işlev (geri arama) bekleyen bir işlev, ilke olarak başka herhangi bir değer de alabilir (veya hiç değer alamaz). Ancak, bu sözde işlevin çağrılması kaçınılmaz olarak bir tür hatasına yol açar (“geri arama bir işlev değildir”). Önceki örneğe göre, aşağıdaki aramalar yapılabilir ancak önerilmez:

doSomething(4711); // Typfehler, da Zahl
doSomething('Max Mustermann'); // Typfehler, da Zeichenkette
doSomething(); // Typfehler, da kein Parameter


Bu nedenle öncelikle fonksiyon içindeki callback parametresinin türünü kontrol etmek ve gerçekten bir fonksiyon olduğundan emin olmak önemlidir. Bu, aracılığıyla elde edilebilir birazoperatör, aşağıdaki listede gösterildiği gibi. Bu, iletilen parametre için “işlev” değerini döndürürse, o zaman bu bir işlevdir ve hiçbir şey sizi onu çağırmaktan alıkoyamaz:

function doSomething(callback) {
/* ... */
if(typeof callback === 'function') {
callback();
}
/* ... */
}

Bir işlev içinde geri arama işlevinin çağrılabileceği birden fazla yer varsa, bu kontrol şu noktalardan önce gelmelidir:

function doSomething(callback) {
/* ... */
if(foo) {
/* ... */
if(typeof callback === 'function') {
callback();
}
} else {
/* ... */
if(typeof callback === 'function') {
callback();
}
}
/* ... */
}

Aşağıdaki listede olduğu gibi, işlevin başında kontrol ederseniz ve geri arama parametresinin bir işlev olmaması durumunda, onu anonim bir boş işlevle yeniden tanımlarsanız bu önlenebilir. Bu basit ama etkili hile, aşağıdaki tüm geri arama işlevi çağrılarını tek seferde güvence altına alır:

function doSomething(callback) {
if(!(typeof callback === 'function')) {
callback = function() {}; // Neudefinition
}
/* ... */
if(foo) {
/* ... */
callback();
} else {
/* ... */
callback();
}
/* ... */
}

Koşullu operatörle bağlantılı olarak, her şey tek bir kod satırına da indirgenebilir:

callback = (typeof callback === 'function') ? callback : function() {};
Geri arama işlevinin parametreleri


Geri arama işlevleri eşzamansız olarak çağrıldığından ve ne doğrudan bir dönüş değeri sağlayabildiğinden ne de hata oluşturamadığından, en azından şu iki durum için uygun parametrelerin sağlanması gerekir: hata durumunda oluşan hata hakkında bilgi içeren bir parametre ve hata durumunda oluşan bir parametre normalde eşzamansız hesaplamanın sonucunu içerir. Prensipte bu iki parametrenin sırası önemli olmasa da, özellikle Node.js modülleri geliştirilirken hatayı birinci parametre, sonucu ikinci parametre olarak listelemek (hata yoksa, sıfıra karşılık gelen ilk parametreler).

doSomething(function(
error, // Erster Parameter: Fehlerobjekt
result // Zweiter Parameter: Ergebnis
) {
});
function doSomething(callback) {
/* ... */
var result = null;
try {
// Code, der Fehler produziert
} catch(error) {
callback(error);
}
callback(null, result);
}

Bir hata oluştuysa, basit bir komutla geri arama işlevi içinde kontrol edilebilir. öz– Soruyu öğrenin:

doSomething(function(error, result) {
if(error) {
// Fehlerbehandlung
} else {
// Normalfall
}
});
Geri arama dönüşü


Bazı durumlarda, önceki örneklerde gösterildiği gibi geri arama işlevlerinin çağrılması istenmeyen program davranışına yol açabilir. Örneğin, sondan bir önceki listede, bir hata durumunda geri arama işlevi iki kez çağrılır. İşte kod tekrar:

function doSomething(callback) {
/* ... */
var result = null;
try {
// Code, der Fehler produziert
} catch(error) {
callback(error);
}
callback(null, result);
}

Buradaki sorun, try-catch bloğundan sonraki kodun her zaman çağrılacak olmasıdır. Catch bloğu daha önce bir hata nedeniyle atlanmış ve geri arama işlevi orada çağrılmış olsa bile. Kaynak kodunu okuyarak kolayca gözden kaçırabileceğiniz bir gerçek. Bu nedenle, her geri arama işlevi çağrısından önce doğrudan çağıran işlevden atlayan bir “dönüş” eklemelisiniz.

function doSomething(callback) {
/* ... */
var result = null;
try {
// Code, der Fehler produziert
} catch(error) {
return callback(error, null);
}
return callback(null, result);
}

Bunun ön koşulu elbette çağıran fonksiyonun buna göre yapılandırılması ve geri çağırma fonksiyonunun çağrılmasının her zaman fonksiyonun sonunu temsil etmesidir. Ve aşağıdaki örnekte gösterildiği gibi veya ondan sonraki kodda değil:

function doSomething(callback) {
/* ... */
var result = null;
try {
// Code, der Fehler produziert
} catch(error) {
return callback(error, null);
}
return callback(null, result);
// Code ab hier wird nie ausgeführt.
if(foo) {
/* ... */
}
}
Geri arama işlevinin yürütme bağlamı


İşlevler, aracılığıyla gönderilen geri arama parametreleri olarak geçirilirken özel dikkat gerekir. Bu yürütme içeriğine erişin. Bu durumda fonksiyona bakmanız gerekir. bağ() ve istenen yürütme bağlamıyla ilişkili yeni bir işlev oluşturun. Ardından bu yeni işlev bir geri arama parametresi olarak iletilir:

var person = {
name: 'Max Mustermann',
printName: function() {
console.log(this.name);
}
}
doSomething(person.printName); // Falsch
var printNameBound = person.printName.bind(person);
doSomething(printNameBound); // Richtig

Çözüm


Geri arama işlevleriyle çalışırken, türün kontrol edilmesi, geri arama parametrelerinin sıralanması, geri arama işlevlerinin bir kez çağrılması ve yürütme bağlamının ayarlanması dahil olmak üzere birkaç en iyi uygulama göz önünde bulundurulmalıdır. Asenkron programlama için, geri arama işlevleri yerine, sözlerin, üretici işlevlerin veya ES7 için planlanan async/await kombinasyonunun kullanılıp kullanılmayacağına dair temel soru bu noktada beklemeye alınır.

Yazar, Rheinwerk Verlag tarafından yayınlanan “Professional Development with JavaScript: Designs, Templates and Practical Tips” adlı kitabında 450 sayfada JavaScript’in profesyonel yazılım geliştirmede nasıl kullanılabileceğini gösteriyor. Konular, işlevsel ve nesne yönelimli programlama, ES6/ES2015’teki yeni özellikler, JavaScript uygulama testi, JavaScript uygulama geliştirme süreci, tasarım kalıpları, mimari kalıplar ve daha fazlasını içerir.


()



Haberin Sonu
 
Üst