web-dev-qa-db-fra.com

Style JavaScript pour les rappels facultatifs

J'ai certaines fonctions qui reçoivent (parfois pas toujours) un rappel et l'exécutent. Est-ce que vérifier si le rappel est défini/fonctionner est un bon style ou existe-t-il une meilleure façon?

Exemple:

function save (callback){
   .....do stuff......
   if(typeof callback !== 'undefined'){
     callback();
   };
};
86
henry.oswald

Je préfère personnellement

typeof callback === 'function' && callback();

La commande typeof est cependant douteuse et ne doit être utilisée que pour "undefined" et "function"

Les problèmes avec le typeof !== undefined est que l'utilisateur peut passer une valeur définie et pas une fonction

131
Raynos

Vous pouvez également faire:

var noop = function(){}; // do nothing.

function save (callback){
   callback = callback || noop;
   .....do stuff......
};

C'est particulièrement utile si vous utilisez le callback à quelques endroits.

De plus, si vous utilisez jQuery, vous avez déjà une fonction comme ça, elle s'appelle $. Noop

45
Pablo Fernandez

Faites simplement

if (callback) callback();

Je préfère appeler le rappel s'il est fourni, quel que soit le type. Ne le laissez pas échouer en silence, afin que l'implémenteur sache qu'il a transmis un argument incorrect et peut le corriger.

33
ninja123

ECMAScript 6

// @param callback Default value is a noop fn.
function save(callback = ()=>{}) {
   // do stuff...
   callback();
}
8
Lucio

Plutôt que de rendre le rappel facultatif, attribuez simplement une valeur par défaut et appelez-la

const identity = x =>
  x

const save (..., callback = identity) {
  // ...
  return callback (...)
}

Lorsqu'elle est utilisée

save (...)              // callback has no effect
save (..., console.log) // console.log is used as callback

Un tel style est appelé style passant-continuation . Voici un exemple réel, combinations, qui génère toutes les combinaisons possibles d'une entrée de tableau

const identity = x =>
  x

const None =
  Symbol ()

const combinations = ([ x = None, ...rest ], callback = identity) =>
  x === None
    ? callback ([[]])
    : combinations
        ( rest
        , combs =>
            callback (combs .concat (combs .map (c => [ x, ...c ])))
        )

console.log (combinations (['A', 'B', 'C']))
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]

Étant donné que combinations est défini dans le style de passage de continuation, l'appel ci-dessus est en fait le même

combinations (['A', 'B', 'C'], console.log)
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]

On peut aussi passer une suite personnalisée qui fait autre chose avec le résultat

console.log (combinations (['A', 'B', 'C'], combs => combs.length))
// 8
// (8 total combinations)

Le style de passage peut être utilisé avec des résultats étonnamment élégants

const first = (x, y) =>
  x

const fibonacci = (n, callback = first) =>
  n === 0
    ? callback (0, 1)
    : fibonacci
        ( n - 1
        , (a, b) => callback (b, a + b)
        )
        
console.log (fibonacci (10)) // 55
// 55 is the 10th fibonacci number
// (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...)
1
user633183

J'étais tellement fatigué de voir ce même extrait encore et encore, j'ai écrit ceci:

  var cb = function(g) {
    if (g) {
      var args = Array.prototype.slice.call(arguments); 
      args.shift(); 
      g.apply(null, args); 
    }
  };

J'ai des centaines de fonctions qui font des choses comme

  cb(callback, { error : null }, [0, 3, 5], true);

ou peu importe...

Je suis sceptique quant à la stratégie globale "assurez-vous que c'est fonctionnel". Les seules valeurs légitimes sont une fonction ou une fausse. Si quelqu'un passe un nombre non nul ou une chaîne non vide, qu'allez-vous faire? Comment ignorer le problème le résout-il?

1
Malvolio

Une fonction valide est basée sur le prototype Function, utilisez:

if (callback instanceof Function)

pour être sûr que le rappel est une fonction

1
G. Moore

Si le critère pour exécuter le rappel est que ce soit défini ou non, alors ça va. Aussi, je suggère de vérifier si c'est vraiment une fonction en plus.

0
Mrchief

Cela peut facilement être fait avec ArgueJS :

function save (){
  arguments = __({callback: [Function]})
.....do stuff......
  if(arguments.callback){
    callback();
  };
};
0
zVictor

Je me suis sincèrement déplacé vers le script de café et j'ai trouvé que les arguments par défaut étaient une bonne façon de résoudre ce problème

doSomething = (arg1, arg2, callback = ()->)->
    callback()
0
henry.oswald