JavaScript'te geri arama işlevlerini daha iyi anlama


163

Bir işlevi geri arama olarak başka bir işleve geçirmeyi ve çalıştırmasını anlıyorum, ancak bunu yapmak için en iyi uygulamayı anlamıyorum. Bunun gibi çok temel bir örnek arıyorum:

var myCallBackExample = {
    myFirstFunction : function( param1, param2, callback ) {
        // Do something with param1 and param2.
        if ( arguments.length == 3 ) {
            // Execute callback function.
            // What is the "best" way to do this?
        }
    },
    mySecondFunction : function() {
        myFirstFunction( false, true, function() {
            // When this anonymous function is called, execute it.
        });
    }
};

MyFirstFunction içinde, yeni geri arama () döndürürsem, o zaman çalışır ve anonim işlevi yürütür, ama bu bana doğru bir yaklaşım gibi görünmüyor.


Hangi anlamda doğru? Genellikle geri çağrılar olay işleyicileri için kullanılır - özellikle asenkron olan Ajax çağrıları - temelde bir yanıtın ne zaman geleceğini (veya geleceğini) bilmediğiniz şeyler.
cletus

2
Bu arada argümanlar dizi gibi ancak dizi değil, bu yüzden argument.length yapamazsınız, ancak dilim yöntemini kullanarak bir diziye dönüştürebilirsiniz ...
paul

1
@paul, doğru argumentsolmasa da bir dizi değildir, yine de uzunluğunu referans olarak kullanabilirsiniz arguments.length- bir deneyin. Bu özellik, gerçekte iletilen bağımsız değişkenlerin sayısını belirtir ve işlev imzasındaki parametrelerin sayısını belirtmez.
hotshot309

Yanıtlar:


132

Sadece söyleyebilirsin

callback();

Alternatif olarak , geri arama içindeki calldeğerini ayarlamak isterseniz yöntemi kullanabilirsiniz this.

callback.call( newValueForThis);

Fonksiyonun thisiçinde ne varsa olurdu newValueForThis.


91

Geri aramanın var olup olmadığını ve yürütülebilir bir işlev olup olmadığını kontrol etmelisiniz:

if (callback && typeof(callback) === "function") {
    // execute the callback, passing parameters as necessary
    callback();
}

Pek çok kütüphane (jQuery, dojo, vb.), Eşzamansız işlevleri için benzer bir desen ve tüm eşzamansız işlevler için node.js kullanır (düğümler genellikle geçer errorve datageri aramaya ). Kaynak kodlarına bakmak yardımcı olacaktır!


Neden callbackdizeye yayın yapıp türünü kontrol ediyorsunuz? Bu performansı artıracak mı? Bu, türü kontrol etmek, dönüştürülen boolean öğesinin true döndürüp döndürmediğini kontrol etmek ve ardından türünü tekrar kontrol etmek ve dizeye karşı test etmek gibidir ... Nedenini açıklayabilir misiniz?
headacheCoder

Geri arama için neden ilk iddiaya ihtiyacınız olduğunu merak ediyorum ... null veya undefined'i kontrol etmek mi? Bunu typeof(callback)senin için başarmaz mıydı? typeof(null) === "Object",typeof("undefined") === "undefined"
PJH

1
Kısa devre VE. Geri arama yoksa, türünü hesaplama zahmetine girmeyin. Yine de haklısın. Typeof () ile gerekli değildir, ancak bir jsperf yapacağım ve kısa devrenin buna değip değmeyeceğini göreceğim.
arunjitsingh

@headacheCoder - callbackbir dizeye yayınlanmıyor, çağrılmadan önce türü bir işlev olup olmadığını görmek için kontrol ediliyor. Kod muhtemelen callbackbir argüman olarak kabul eder ve argümanın çağrılabilir bir tipte olduğundan emin değildir - ya da belki de argümanlar, kodun farklı typeofargümanlara farklı tepki verebileceği bir tür polimorfizm sağlama girişiminde çeşitli türlerde olduğundan emin değildir .
LeeGee

34

Bir işlevi yerine getirmek için 3 ana olasılık vardır:

var callback = function(x, y) {
    // "this" may be different depending how you call the function
    alert(this);
};
  1. geri arama (bağımsız değişken_1, bağımsız değişken_2);
  2. callback.call (some_object, argüman_1, argüman_2);
  3. callback.apply (some_object, [argument_1, argument_2]);

Seçtiğiniz yöntem şunlara bağlıdır:

  1. Array öğesinde veya bağımsız değişkenler olarak depolanan bağımsız değişkenlere sahipsiniz.
  2. Bu işlevi bir nesne bağlamında çağırmak istiyorsunuz. Bu durumda, bu geri çağrıda "this" anahtar sözcüğünü kullanmak, call () öğesinde argüman olarak iletilen nesneye veya Apply () öğesine başvuruda bulunur. Nesne içeriğini geçirmek istemiyorsanız, null veya undefined kullanın. İkinci durumda, global nesne "bu" için kullanılır.

Function.call , Function.apply için Dokümanlar


6

Geri aramalar sinyallerle ilgilidir ve "yeni" nesne örnekleri oluşturmakla ilgilidir.

Bu durumda, sadece "callback ();" "return new callback ()" yerine, geri dönüş değeri olan hiçbir şey yapmıyorsunuz.

(Ve arguments.length == 3 testi gerçekten tıknaz, fwiw, geri arama parametresinin var olduğunu ve bir işlev olduğunu kontrol etmek daha iyidir.)


6

uygun uygulama:

if( callback ) callback();

bu geri arama parametresini isteğe bağlı yapar.


Geri çağrı argümanı bir işlev değilse ne olur?
Yaki Klein

2

Kullanabilirsiniz:

if (callback && typeof(callback) === "function") {
    callback();
}

Aşağıdaki örnek biraz daha kapsamlıdır:

function mySandwich(param1, param2, callback) {
  alert('Started eating my sandwich.\n\nIt has: ' + param1 + ', ' + param2);
  var sandwich = {
      toppings: [param1, param2]
    },
    madeCorrectly = (typeof(param1) === "string" && typeof(param2) === "string") ? true : false;
  if (callback && typeof(callback) === "function") {
    callback.apply(sandwich, [madeCorrectly]);
  }
}

mySandwich('ham', 'cheese', function(correct) {
  if (correct) {
    alert("Finished eating my " + this.toppings[0] + " and " + this.toppings[1] + " sandwich.");
  } else {
    alert("Gross!  Why would I eat a " + this.toppings[0] + " and " + this.toppings[1] + " sandwich?");
  }
});


1

callback()JavaScript'teki işlevi açıklayan temel bir örnek :

var x = 0;

function testCallBack(param1, param2, callback) {
  alert('param1= ' + param1 + ', param2= ' + param2 + ' X=' + x);
  if (callback && typeof(callback) === "function") {
    x += 1;
    alert("Calla Back x= " + x);
    x += 1;
    callback();
  }
}

testCallBack('ham', 'cheese', function() {
  alert("Function X= " + x);
});

JSFiddle


1

function checkCallback(cb) {
  if (cb || cb != '') {
    if (typeof window[cb] === 'undefined') alert('Callback function not found.');
    else window[cb].call(this, Arg1, Arg2);
  }
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.