Question

J'écris un "module" global de gestion des erreurs. pour l'une de mes applications.

Une des fonctionnalités que je souhaite avoir est de pouvoir encapsuler facilement une fonction avec un bloc try {} catch {} , de sorte que le traitement des erreurs soit automatiquement appliqué à tous les appels de cette fonction. code qui appellera ma méthode de journalisation globale. (Pour éviter de polluer le code partout avec des blocs try / catch).

Cependant, je ne comprends pas du tout le fonctionnement de bas niveau de JavaScript, les méthodes .call et .apply , et le this mot clé.

J'ai écrit ce code, basé sur la méthode Function.wrap de Prototype:

Object.extend(Function.prototype, {
  TryCatchWrap: function() {
    var __method = this;
    return function() {
            try { __method.apply(this, arguments) } catch(ex) { ErrorHandler.Exception(ex); }
    }
  }
});

Ce qui est utilisé comme ceci:

function DoSomething(a, b, c, d) {
    document.write(a + b + c)
    alert(1/e);
}

var fn2 = DoSomething.TryCatchWrap();
fn2(1, 2, 3, 4);

Ce code fonctionne parfaitement. Il en imprime 6, puis appelle mon gestionnaire d’erreurs global.

Ma question est la suivante: est-ce que cela va casser quelque chose quand la fonction que je suis en train de boucler est dans un objet, et elle utilise le "ceci" opérateur? Je suis un peu inquiet puisque j'appelle .appliquer, en passant quelque chose, je crains que cela ne casse quelque chose.

Était-ce utile?

La solution

Personnellement, au lieu de polluer les objets intégrés, je choisirais une technique de décorateur:

var makeSafe = function(fn){
  return function(){
    try{
      return fn.apply(this, arguments);
    }catch(ex){
      ErrorHandler.Exception(ex);
    }
  };
};

Vous pouvez l'utiliser comme ça:

function fnOriginal(a){
  console.log(1/a);
};

var fn2 = makeSafe(fnOriginal);
fn2(1);
fn2(0);
fn2("abracadabra!");

var obj = {
  method1: function(x){ /* do something */ },
  method2: function(x){ /* do something */ }
};

obj.safeMethod1 = makeSafe(obj.method1);
obj.method1(42);     // the original method
obj.safeMethod1(42); // the "safe" method

// let's override a method completely
obj.method2 = makeSafe(obj.method2);

Mais si vous avez envie de modifier des prototypes, vous pouvez l'écrire comme ça:

Function.prototype.TryCatchWrap = function(){
  var fn = this; // because we call it on the function itself
  // let's copy the rest from makeSafe()
  return function(){
    try{
      return fn.apply(this, arguments);
    }catch(ex){
      ErrorHandler.Exception(ex);
    }
  };
};

Une amélioration évidente consistera à paramétrer makeSafe () afin de pouvoir spécifier la fonction à appeler dans le bloc catch.

Autres conseils

Réponse de 2017 : utilisez simplement ES6. Étant donné la fonction de démonstration suivante:

var doThing = function(){
  console.log(...arguments)
}

Vous pouvez créer votre propre fonction wrapper sans avoir besoin de bibliothèques externes:

var wrap = function(someFunction){
  var wrappedFunction = function(){
    var args = [...arguments].splice(0)
    console.log(`You're about to run a function with these arguments: \n     ${args}`)
    return someFunction(args)
  }
  return wrappedFunction
}

En cours d'utilisation:

doThing = wrap(doThing)

doThing('one', {two:'two'}, 3)

Réponse de 2016 : utilisez le module wrap :

Dans l'exemple ci-dessous, j'emballe process.exit () , mais cela fonctionne sans problème avec toute autre fonction (y compris le navigateur JS également).

var wrap = require('lodash.wrap');

var log = console.log.bind(console)

var RESTART_FLUSH_DELAY = 3 * 1000

process.exit = wrap(process.exit, function(originalFunction) {
    log('Waiting', RESTART_FLUSH_DELAY, 'for buffers to flush before restarting')
    setTimeout(originalFunction, RESTART_FLUSH_DELAY)
});

process.exit(1);

Object.extend (Function.prototype, { Object.extend dans la console Google Chrome m'indique "non défini". Eh bien voici quelques exemples de travail:

    Boolean.prototype.XOR =
//  ^- Note that it's a captial 'B' and so
//      you'll work on the Class and not the >b<oolean object
        function( bool2 ) { 

           var bool1 = this.valueOf();
           //         'this' refers to the actual object - and not to 'XOR'

           return (bool1 == true   &&   bool2 == false)
               || (bool1 == false   &&   bool2 == true);
        } 

alert ( "true.XOR( false ) => " true.XOR( false ) );

donc au lieu de Object.extend (Function.prototype, {...}) Faites-le comme: Function.prototype.extend = {}

L'emballage de fonctions à l'ancienne:

//Our function
function myFunction() {
  //For example we do this:
  document.getElementById('demo').innerHTML = Date();
  return;
}

//Our wrapper - middleware
function wrapper(fn) {
  try {
    return function(){
      console.info('We add something else', Date());
      return fn();
    }
  }
  catch (error) {
    console.info('The error: ', error);
  }
}

//We use wrapper - middleware
myFunction = wrapper(myFunction);

Idem dans le style ES6:

//Our function
let myFunction = () => {
  //For example we do this:
  document.getElementById('demo').innerHTML = Date();
  return;
}

//Our wrapper - middleware
const wrapper = func => {
  try {
    return () => {
      console.info('We add something else', Date());
      return func();
    }
  }
  catch (error) {
    console.info('The error: ', error);
  }
}

//We use wrapper - middleware
myFunction = wrapper(myFunction);

En ce qui concerne la pollution des espaces de noms, je vais les polluer encore plus ... Puisque tout ce qui se passe dans JS est initié par un événement quelconque, je prévois d'appeler ma fonction wrapper magique depuis la méthode Prototype Event.observe (). Je n'ai donc pas besoin de l'appeler partout.

Je vois les inconvénients de tout cela, bien sûr, mais ce projet en particulier est fortement lié à Prototype de toute façon, et je souhaite que ce code de gestionnaire d'erreurs soit aussi global que possible, afin que ce ne soit pas un gros problème.

Merci pour votre réponse!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top