Comprendere meglio le funzioni di callback in JavaScript


163

Comprendo il passaggio di una funzione a un'altra funzione come callback e la sua esecuzione, ma non capisco la migliore implementazione per farlo. Sto cercando un esempio molto semplice, come questo:

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

In myFirstFunction, se restituisco un nuovo callback (), allora funziona ed esegue la funzione anonima, ma non mi sembra l'approccio corretto.


Corretto in che senso? In genere i callback sono usati per i gestori di eventi - in particolare le chiamate Ajax, che sono asincrone - in pratica cose in cui non si sa quando (o se) verrà un resposne.
cletus,

2
tra l'altro gli argomenti sono array come ma non array, quindi non puoi fare topic.length ma puoi convertirlo in un array usando il metodo slice ...
paul

1
@paul, anche se hai ragione che argumentsnon è un array, puoi comunque fare riferimento alla sua lunghezza come arguments.length- provalo. Questa proprietà si riferisce al numero di argomenti effettivamente passati e non necessariamente al numero di parametri nella firma della funzione.
hotshot309

Risposte:


132

Puoi solo dire

callback();

In alternativa, è possibile utilizzare il callmetodo se si desidera regolare il valore thisall'interno del callback.

callback.call( newValueForThis);

All'interno della funzione ci thissarebbe qualunque cosa newValueForThissia.


91

È necessario verificare se il callback esiste ed è una funzione eseguibile:

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

Molte librerie (jQuery, dojo, ecc.) Usano un modello simile per le loro funzioni asincrone, così come node.js per tutte le funzioni asincrone (di solito nodejs passa errore dataal callback). Analizzare il loro codice sorgente sarebbe di aiuto!


Perché esegui il cast callbacksu stringa e quindi ne controlli il tipo? Ciò migliorerà le prestazioni? È come controllare il tipo, verificare se il valore booleano convertito restituisce true e quindi ricontrollare il suo tipo e testarlo sulla stringa ... Potresti spiegare perché?
mal di

Sono curioso di sapere perché hai bisogno della prima asserzione per il callback ... è da controllare null o indefinito? Non lo typeof(callback)otterresti per te? typeof(null) === "Object",typeof("undefined") === "undefined"
PJH,

1
Corto circuito AND. Se il callback non esiste, non preoccuparti di calcolare il suo tipo. Tuttavia, hai ragione. Non è necessario con typeof (), ma farò un jsperf e vedrò se ne vale la pena.
Arunjitsingh,

@headacheCoder - callbacknon viene trasmesso su una stringa, il suo tipo viene controllato per vedere se è una funzione, prima che venga chiamata. Il codice presumibilmente accetta callbackcome argomento ed è incerto che l'argomento sia di tipo richiamabile - o forse gli argomenti sono di vario tipo nel tentativo di fornire una forma di polimorfismo in cui il codice potrebbe reagire in modo diverso a diversi typeofargomenti.
LeeGee,

34

Esistono 3 possibilità principali per eseguire una funzione:

var callback = function(x, y) {
    // "this" may be different depending how you call the function
    alert(this);
};
  1. callback (argomento_1, argomento_2);
  2. callback.call (some_object, argomento_1, argomento_2);
  3. callback.apply (some_object, [argomento_1, argomento_2]);

Il metodo scelto dipende se:

  1. Gli argomenti sono archiviati in una matrice o come variabili distinte.
  2. Vuoi chiamare quella funzione nel contesto di qualche oggetto. In questo caso, l'utilizzo della parola chiave "this" in quel callback farebbe riferimento all'oggetto passato come argomento in call () o apply (). Se non si desidera passare il contesto dell'oggetto, utilizzare null o non definito. In quest'ultimo caso l'oggetto globale verrebbe utilizzato per "questo".

Documenti per Function.call , Function.apply


6

I callback riguardano i segnali e "new" riguarda la creazione di istanze di oggetti.

In questo caso sarebbe ancora più appropriato eseguire solo "callback ();" di "return new callback ()" perché non stai facendo nulla con un valore di ritorno comunque.

(E il test argomenti.length == 3 è davvero goffo, prima di tutto, è meglio controllare che esista il parametro callback ed è una funzione.)


6

la corretta attuazione sarebbe:

if( callback ) callback();

questo rende facoltativo il parametro callback.


Cosa succede se l'argomento callback non è una funzione?
Yaki Klein,

2

Puoi usare:

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

L'esempio seguente è un po 'più completo:

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

Ecco un esempio di base che spiega la callback()funzione in 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);
  }
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.