Frage

Ich schreibe ein "Modul" globaler Fehlerhandling für eine meiner Anwendungen.

Eine der Funktionen, die ich haben möchte try{} catch{} Blockieren, damit alle Aufrufe dieser Funktion automatisch den Fehlerbehandlungscode haben, der meine globale Protokollierungsmethode aufruft. (Um zu vermeiden, dass der Code mit Try/Catch -Blöcken überall verschmutzt wird).

Dies geht jedoch leicht über mein Verständnis der niedrigen Funktionen von JavaScript hinaus, die .call und .apply Methoden und die this Stichwort.

Ich habe diesen Code basierend auf Prototypen geschrieben Function.wrap Methode:

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

Welches wird so verwendet:

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

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

Dieser Code funktioniert perfekt. Es druckt 6 aus und ruft dann meinen globalen Fehlerhandler auf.

Meine Frage lautet: Wird dies etwas brechen, wenn die von mir wickelende Funktion in einem Objekt liegt und den "diesen" Operator verwendet? Ich mache mir ein wenig Sorgen, da ich anrufe. Apply, ich befürchte, dass dies etwas brechen könnte.

War es hilfreich?

Lösung

Persönlich würde ich mit einer Dekoratextechnik anstatt umgebaute Objekte zu verschmutzen:

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

Sie können es so verwenden:

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

Wenn Sie jedoch Prototypen modifizieren möchten, können Sie es so schreiben:

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

Eine offensichtliche Verbesserung wird darin bestehen, makeafe () zu parametriieren, damit Sie angeben können, welche Funktion im Catch -Block aufgerufen werden soll.

Andere Tipps

2017 Antwort: Verwenden Sie einfach ES6. Angesichts der folgenden Demo -Funktion:

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

Sie können Ihre eigene Wrapper -Funktion erstellen, ohne externe Bibliotheken zu benötigen:

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
}

In Benutzung:

doThing = wrap(doThing)

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

2016 Antwort: Verwenden Sie die wrap Modul:

Im folgenden Beispiel wicke ich ein process.exit(), Aber dies funktioniert glücklich mit jeder anderen Funktion (einschließlich Browser -JS).

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 In der Google Chrome -Konsole gibt ich "undefined" hier ein funktionierendes Beispiel:

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

Also anstelle von Object.extend (function.Prototype, {...}) tun Sie es wie: function.prototype.extend = {}

Funktionswickel auf gute alte Mode:

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

Das gleiche gilt im ES6 -Stil:

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

Was die Verschmutzung der Namespaces angeht, werde ich sie tatsächlich noch mehr verschmutzen ... da alles, was in JS passiert .OBSERVE () Methode, also muss ich es nicht überall anrufen.

Ich sehe natürlich die Nachteile von all dem, aber dieses spezielle Projekt ist trotzdem stark mit dem Prototyp verbunden, und ich möchte, dass dieser Fehlerhandlercode so global wie möglich ist, also ist es keine große Sache.

Danke für deine Antwort!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top