Mieux comprendre les fonctions de rappel en JavaScript

163

Je comprends le passage d'une fonction à une autre fonction en tant que rappel et son exécution, mais je ne comprends pas la meilleure implémentation pour le faire. Je recherche un exemple très basique, comme celui-ci:

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

Dans myFirstFunction, si je retourne new callback (), cela fonctionne et exécute la fonction anonyme, mais cela ne me semble pas être la bonne approche.


la source
Correct dans quel sens? Les rappels sont généralement utilisés pour les gestionnaires d'événements - notamment les appels Ajax, qui sont asynchrones - essentiellement des choses où vous ne savez pas quand (ou si) une resposne arrivera.
cletus
2
par la façon dont les arguments sont comme un tableau mais pas un tableau, donc vous ne pouvez pas faire argument.length mais vous pouvez le convertir en un tableau en utilisant la méthode slice ...
paul
1
@paul, bien que vous ayez raison de dire que ce argumentsn'est pas un tableau, vous pouvez toujours référencer sa longueur comme arguments.length- essayez-le. Cette propriété fait référence au nombre d'arguments réellement passés et pas nécessairement au nombre de paramètres dans la signature de la fonction.
hotshot309

Réponses:

132

Tu peux juste dire

callback();

Vous pouvez également utiliser la callméthode si vous souhaitez ajuster la valeur de thisdans le rappel.

callback.call( newValueForThis);

À l'intérieur de la fonction se thistrouverait ce qui newValueForThisest.

Krosenvold
la source
91

Vous devez vérifier si le rappel existe et est une fonction exécutable:

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

Beaucoup de bibliothèques (jQuery, Dojo, etc.) utilisent un modèle similaire pour leurs fonctions asynchrones, ainsi que Node.js pour toutes les fonctions asynchrones (NodeJS passe habituellement erroret dataau rappel). Examiner leur code source aiderait!

arunjitsingh
la source
Pourquoi transtypez-vous en callbackchaîne puis vérifiez son type? Cela améliorera-t-il les performances? C'est comme vérifier le type, vérifier si le booléen converti renvoie true, puis vérifier à nouveau son type et le tester par rapport à la chaîne ... Pouvez-vous expliquer pourquoi?
headacheCoder
Je suis curieux de savoir pourquoi vous avez besoin de la première assertion pour le rappel ... est-ce pour vérifier null ou indéfini? N'y arriverait-il pas typeof(callback)pour vous? typeof(null) === "Object",typeof("undefined") === "undefined"
PJH
1
Court-circuit ET. Si le rappel n'existe pas, ne vous souciez pas de calculer son type. Mais tu as raison. Ce n'est pas nécessaire avec le typeof (), mais je vais faire un jsperf et voir si le court-circuit en vaut la peine.
arunjitsingh le
@headacheCoder - callbackn'est pas converti en chaîne, son type est vérifié pour voir s'il s'agit d'une fonction, avant qu'elle ne soit appelée. Le code accepte vraisemblablement callbackcomme argument, et n'est pas certain que l'argument soit d'un type appelable - ou peut-être que les arguments sont de différents types dans une tentative de fournir une forme de polymorphisme où le code pourrait réagir différemment à différents typeofarguments.
LeeGee
34

Il existe 3 possibilités principales pour exécuter une fonction:

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

La méthode que vous choisissez dépend si:

  1. Vous avez les arguments stockés dans un tableau ou en tant que variables distinctes.
  2. Vous souhaitez appeler cette fonction dans le contexte d'un objet. Dans ce cas, l'utilisation du mot clé "this" dans ce rappel ferait référence à l'objet passé en argument dans call () ou apply (). Si vous ne souhaitez pas transmettre le contexte de l'objet, utilisez null ou undefined. Dans ce dernier cas, l'objet global serait utilisé pour «ceci».

Docs pour Function.call , Function.apply

Ionuț G. Stan
la source
6

Les rappels concernent les signaux et «nouveau» concerne la création d'instances d'objets.

Dans ce cas, il serait encore plus approprié d'exécuter simplement "callback ();" que "return new callback ()" car vous ne faites rien avec une valeur de retour de toute façon.

(Et le test arguments.length == 3 est vraiment maladroit, fwiw, mieux vaut vérifier que le paramètre de rappel existe et est une fonction.)

Annakata
la source
6

la mise en œuvre appropriée serait:

if( callback ) callback();

cela rend le paramètre de rappel facultatif.

faeb187
la source
Que faire si l'argument de rappel n'est pas une fonction?
Yaki Klein
2

Vous pouvez utiliser:

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

L'exemple ci-dessous est un peu plus complet:

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

Hasan A Yousef
la source
1

Voici un exemple de base qui explique la callback()fonction en 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

BERGUIGA Mohamed Amine
la source
1

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

Aamir Afridi
la source