2015-02-20 3 views
8

Ich habe mehrere Meteor.calls, wobei jede Methode von der Antwort einer anderen Meteor-Methode abhängt.Vermeiden Callback Hell mit mehreren Meteor Methodenaufrufen auf Client

Kunde

Meteor.call('methodOne', function(err, resOne){ 
    if(!err){ 
     Meteor.call('methodTwo', resOne, function(err, resTwo){ 
      if(!err){ 
       Meteor.call('methodThree', resTwo, function(err, resThree){ 
        if(err){ 
         console.log(err); 
        } 
       }) 
      } 
     }); 
    } 
}); 

Von Meteor Dokumentation Ich weiß

„auf dem Client läuft genannt Methoden asynchron, so dass Sie einen Rückruf, um passieren müssen das Ergebnis des Aufrufs zu beobachten.“

Ich weiß, dass ich eine weitere Meteor-Methode auf dem Server erstellen kann, um die Methoden 'methodOne', 'MethodTwo', 'MethodThree' mit Meteor.async oder sequentiell ohne Callback auszuführen. Aber ich bin besorgt, dass dieser Weg meine Meteormethoden dazu bringen wird, aufgebläht und verstrickt zu werden, was zu Spaghetti-Code führt. Ich würde lieber jede Meteor Methode einfach mit einem Job machen und eine elegantere Methode finden, die Anrufe auf dem Client zu verketten. Irgendwelche Ideen, gibt es eine Möglichkeit, Promises auf dem Client zu verwenden?

Antwort

13

Da die andere Antwort schlägt RSVP diese Antwort wird Bluebird vorschlagen, welche tatsächlich die schnellste Versprechen Bibliothek ist, wenn real benchmarks läuft. Anstatt amicrobenchmark misst das wirklich nichts Sinnvolles. Wie auch immer, ich wähle es nicht für die Leistung, ich nehme es hier, weil es auch am einfachsten zu verwenden ist und das mit der besten Debuggability.

Im Gegensatz zur anderen Antwort unterdrückt dieser auch keine Fehler und die Kosten für die Rückgabe der Funktion sind marginal, da kein Promise-Konstruktor aufgerufen wird.

var call = Promise.promisify(Meteor.call, Meteor); 

var calls = call("methodOne"). 
      then(call.bind(Meteor, "methodTwo")). 
      then(call.bind(Meteor, "methodThree")); 

calls.then(function(resThree){ 
    console.log("Got Response!", resThree); 
}).catch(function(err){ 
    console.log("Got Error", err); 
}); 
+2

Ich kann ehrlich sagen, dass ich etwas gelernt habe - ich habe nie wirklich versprochen und/oder Verkettung Versprechungen, aber wenn mehr als nur sehr einfache Fälle ins Spiel kommen, scheint Bluebird tatsächlich die beste Wahl, nicht nur Leistung. Vielen Dank! – bardzusny

+0

@benjamin funktioniert dies mit Fasern innerhalb der serverseitigen Methodenaufruf? Ich mache externe http.get-Anrufe und die Rückgabe von Fasern ist ein Versprechen. –

+1

@JasonCochran sicher, es würde funktionieren - obwohl ein "mehr Meteor" Weg wäre "Meteor.wrapAsync" und verwenden Sie den Code, als ob es synchron ist. Die "Versprechungsantwort" dazu verwendet Generatoren und Koroutinen (Bluebird.coroutine). Persönlich bevorzuge ich die Versprechen Version, aber beide sind lebensfähig (wie einfache Rückrufe). Nur um extra klar zu sein - es würde funktionieren. –

3

EDIT: Sie sind wahrscheinlich besser dran @Benjamin Gruenbaum Antwort, die nicht nur in bessere Leistung führt, sondern bietet auch viel prägnanter Code.

Versprechen - ja, es gibt.

Ich mag RSVP sehr viel, warum? Einfach weil es das schnellste ist. (schneller Benchmark: jsperf).

Hier sind schnelle Re-write des Codes:

var promise = new RSVP.Promise(function(fulfill, reject) { 
    Meteor.call('methodOne', '', function(err, resOne) { 
    if (!err) { 
     return reject(err); 
    } 
    fulfill(resOne); 
    }); 
}); 

promise.then(function(resOne) { 
    return new RSVP.Promise(function(fulfill, reject) { 
    Meteor.call('methodTwo', resOne, function(err, resTwo) { 
     if (err) { 
     return reject(err); 
     } 
     fulfill(resTwo); 
    }); 
    }); 
}).then(function(resTwo) { 
    return new RSVP.Promise(function(fulfill, reject) { 
    Meteor.call('methodTwo', resTwo, function(err, resThree) { 
     if (err) { 
     reject(err); 
     } 
     fulfill(resThree); 
    }); 
    }); 
}).then(function(resThree) { 
    // resThree is available - continue as you like 
    console.log(resThree); 
}).catch(function(err) { 
    console.log(err); 
}); 

Das ist der Weg, „die immer nach rechts driften“ des Codes zu verhindern.

Versprechen sind cool, verwenden Sie sie.

+1

RSVP ist keineswegs das schnellste. Dieser Benchmark ist gebrochen, da er das JIT nicht aufruft. Der JSPerf zeigt nichts an. Außerdem - Bluebird wird in diesem Beispiel viel viel schneller als RSVP sein, da Sie die Funktion manuell empfehlen, die eine andere Schließung zuweist. Sie ignorieren auch Fehler, aber das ist eine andere Geschichte. –

+1

Der Benchmark misst die Latenz des verwendeten Schedulers (den Sie mit setScheduler bei Verwendung von bluebird setzen können), nicht die Leistung von Versprechungen. – Esailija

+1

Auch für den Fall, dass Sie nicht bemerkt haben, ist Ihr Code viel komplizierter und ausführlicher als der ursprüngliche Callback-Code .. Wenn er einfach "rechts Drift" des Codes entfernen wollte, die trivial gewesen wäre, indem Sie die Callbacks benannt. – Esailija

3

Ihr Ansatz auf dem Client führt zu viel mehr Rundreisen zwischen dem Server und dem Browser. Ich weiß, dass Sie angegeben haben, dass Sie sich Sorgen über Spaghetti Code auf dem Server gemacht haben und ich habe keinen Einblick in Ihre Anwendung wie Sie, aber durch das von Ihnen bereitgestellte Beispiel scheint es ein idealer Ort zu sein, um alle drei Anrufe auf die Server und mache nur einen Anruf vom Client, IMHO.

+0

+1, ich glaube nicht, dass dies die Antwort auf diese Frage ist, aber nachdem ich ein wenig mehr Arbeit und Forschung gemacht habe, stimme ich zu, dass dies die beste Methode in Verbindung mit einem robusten Designmuster ist, um all Ihre App-Meteor-Methoden zu verwalten. – Robin

+0

Danke. Aber ich denke, es beantwortet Ihre Frage. Es "meidet Rückruf-Hölle" und ist das beste Design für den Beispielcode, den Sie zeigten. –

Verwandte Themen