Lepsze zrozumienie funkcji wywołania zwrotnego w JavaScript


163

Rozumiem przekazywanie funkcji do innej funkcji jako wywołanie zwrotne i zlecanie jej wykonania, ale nie rozumiem najlepszej implementacji do tego. Szukam bardzo podstawowego przykładu, takiego jak ten:

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.
        });
    }
};

W funkcji myFirstFunction, jeśli zwracam new callback (), to działa i wykonuje anonimową funkcję, ale wydaje mi się, że nie jest to właściwe podejście.


Poprawne w jakim sensie? Zwykle wywołania zwrotne są używane do obsługi zdarzeń - w szczególności wywołań Ajax, które są asynchroniczne - w zasadzie rzeczy, w których nie wiesz, kiedy (lub czy) nadejdzie odpowiedź.
— cletus

2
tak przy okazji, argumenty są podobne do tablicy, ale nie do tablicy, więc nie możesz zrobić argument.length, ale możesz przekonwertować ją na tablicę za pomocą metody slice ...
— paul

1
@paul, chociaż masz rację, że argumentsnie jest to tablica, nadal możesz odwołać się do jej długości jako arguments.length- spróbuj. Ta właściwość odnosi się do liczby faktycznie przekazanych argumentów, a niekoniecznie liczby parametrów w sygnaturze funkcji.
— hotshot309

Odpowiedzi:


132

Możesz po prostu powiedzieć

callback();

Alternatywnie możesz użyć tej callmetody, jeśli chcesz dostosować wartość thisw wywołaniu zwrotnym.

callback.call( newValueForThis);

Wewnątrz funkcji thisbyłoby cokolwiek newValueForThisjest.


91

Powinieneś sprawdzić, czy callback istnieje i czy jest funkcją wykonywalną:

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

Wiele bibliotek (jQuery, dojo itp.) Używa podobnego wzorca dla swoich funkcji asynchronicznych, a także node.js dla wszystkich funkcji asynchronicznych (nodejs zwykle przekazuje errori datado wywołania zwrotnego). Zajrzenie do ich kodu źródłowego mogłoby pomóc!


Dlaczego rzucasz callbackna string, a potem sprawdzasz jego typ? Czy to poprawi wydajność? Jest to podobne do sprawdzania typu, sprawdzania, czy przekonwertowana wartość logiczna zwraca wartość true, a następnie ponownego sprawdzania jej typu i porównywania z ciągiem znaków… Czy możesz wyjaśnić, dlaczego?
— headacheCoder

Jestem ciekawy, dlaczego potrzebujesz pierwszego potwierdzenia do wywołania zwrotnego ... czy ma to sprawdzić wartość null czy undefined? Nie typeof(callback)osiągnąłbyś tego dla siebie? typeof(null) === "Object",typeof("undefined") === "undefined"
— PJH,

1
Zwarcie AND. Jeśli wywołanie zwrotne nie istnieje, nie przejmuj się obliczaniem jego typu. Chociaż masz rację. Nie jest to potrzebne w przypadku typeof (), ale zrobię jsperf i zobaczę, czy zwarcie jest tego warte.
— arunjitsingh

@headacheCoder - callbacknie jest rzutowany na ciąg, jego typ jest sprawdzany, aby sprawdzić, czy jest to funkcja, zanim zostanie wywołana. Kod przypuszczalnie akceptuje callbackjako argument i nie jest pewien, czy argument jest typu wywoływalnego - lub być może argumenty są różnego typu w celu zapewnienia formy polimorfizmu, w której kod mógłby różnie reagować na różne typeofargumenty.
— LeeGee,

34

Istnieją 3 główne możliwości wykonania funkcji:

var callback = function(x, y) {
    // "this" may be different depending how you call the function
    alert(this);
};
  1. callback (argument_1, argument_2);
  2. callback.call (jakiś_obiekt, argument_1, argument_2);
  3. callback.apply (jakiś_obiekt, [argument_1, argument_2]);

Wybrana metoda zależy od tego, czy:

  1. Masz argumenty przechowywane w tablicy lub jako odrębne zmienne.
  2. Chcesz wywołać tę funkcję w kontekście jakiegoś obiektu. W takim przypadku użycie słowa kluczowego „this” w tym wywołaniu zwrotnym spowoduje odniesienie do obiektu przekazanego jako argument w funkcji call () lub apply (). Jeśli nie chcesz przekazywać kontekstu obiektu, użyj wartości null lub undefined. W tym drugim przypadku obiekt globalny zostałby użyty do „tego”.

Dokumenty dla funkcji Function.call , Function.apply


6

Wywołania zwrotne dotyczą sygnałów, a „nowy” dotyczy tworzenia instancji obiektów.

W tym przypadku byłoby jeszcze bardziej odpowiednie wykonanie po prostu „callback ()”; niż „return new callback ()”, ponieważ i tak nie robisz nic z wartością zwracaną.

(A arguments.length == 3 test jest naprawdę niezgrabny, fwiw, lepiej sprawdzić, czy parametr wywołania zwrotnego istnieje i jest funkcją.)


6

właściwa realizacja to:

if( callback ) callback();

dzięki temu parametr wywołania zwrotnego jest opcjonalny.


A jeśli argument wywołania zwrotnego nie jest funkcją?
— Yaki Klein

2

Możesz użyć:

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

Poniższy przykład jest trochę bardziej wszechstronny:

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

Oto podstawowy przykład wyjaśniający callback()funkcję w JavaScript:

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);
  }
}

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.