Mongoose: Möglichkeit anzugeben, welche ES6-Versprechungsbibliothek Mongoose verwendet

Erstellt am 17. Feb. 2015  ·  45Kommentare  ·  Quelle: Automattic/mongoose

Siehe Diskussion zu #1699

Hilfreichster Kommentar

Yup require('mongoose').Promise = global.Promise wird Mongoose dazu bringen, native Versprechungen zu verwenden. Sie sollten zwar jeden ES6-Versprechenskonstruktor verwenden können, aber im Moment testen wir nur mit nativen, Bluebird und Q

Alle 45 Kommentare

Ich freue mich wirklich darauf, Promise.all() verwenden zu können, um etwas zu tun, nachdem alle Datenbankarbeiten erledigt sind.

:+1:

Eine Sache, die auf https://github.com/LearnBoost/mongoose/issues/1699 nicht sehr klar war, ist, welche Implementierung die Standardeinstellung sein wird.

Nun, da es sich nicht um eine rückwärtsbrechende Version handelt, muss mpromise die Standardeinstellung sein, aber Sie können sie überschreiben.

+1

:+1:

Gibt es einen Zweig, in dem dies gehackt wird? Ich kann den Fehlerbehandlungsfluss mit mpromise nicht ertragen und bin dabei, die Quelle zu knacken, um zu sehen, was dies erfordern würde.

versprechen:

  query.exec()
    .then(function(ou) {
      if(!ou) {
        return next(new errors.http.NotFound('The specified OU was either not found, or your credentials lack the required permissions to view it.'));
      }

      res.send(ou);
    }, next)
    .end(next);

Muss mit der Ablehnung umgehen und dort auch end eintragen. Ohne end werden Ausnahmen (zum Beispiel hatte ich die NotFound-Klasse falsch geschrieben) stillschweigend geschluckt und drücken nur Verzögerungen aus.

Drossel:

  query.exec()
    .then(function(ou) {
      if(!ou) {
        return next(new errors.http.NotFound('The specified OU was either not found, or your credentials lack the required permissions to view it.'));
      }

      res.send(ou);
    })
    .catch(next);

promisifyAll(require('mongoose')) zu machen scheint eigentlich immer noch mit Mongoose 4 zu arbeiten. Wären Regressionstests, die dies abdecken, zu zielgerichtet?

Nicht im Moment. Die meiste Arbeit wird im Kareem -Modul gemäß #2754 und vkarpov15/kareem#2 stattfinden, denn das wird es uns ermöglichen, zwei Fliegen mit einer Klappe zu schlagen und den wirklich chaotischen Point-Cut-Unsinn zu entfernen, der geschrieben wurde, um Haken und Versprechungen zu machen zusammenarbeiten. Fühlen Sie sich frei, es zu versuchen, ich bin offen für PRs.

Aber warum sollten wir die Unterstützung für andere Versprechungen in der Bibliothek aufbewahren? Die ES6 Promises-Spezifikation ist jetzt felsenfest und hier, um zu bleiben. Können wir nicht einfach reine ES6-Versprechen mit geladenem Polyfill verwenden, wenn sie in älteren Node-Versionen nicht verfügbar sind?

Wenn ja, kann ich es mal versuchen.

Der Punkt ist, dass Sie jede beliebige ES6-kompatible Promises-Bibliothek verwenden können. Viele Leute sind immer noch stark in bluebird, when, q, rsvp, etc. etc. investiert, und jede dieser Bibliotheken hat ihre eigenen Macken, die ein generisches Polyfill nicht erfassen kann.

Ich bin offen für alternative Vorschläge - ich mag oder verwende Versprechungen nicht besonders, diese Funktion ist motiviert durch die Tatsache, dass es einen Berg von Problemen gibt, bei denen Leute nach "Unterstützung von Bluebird Feature X in mpromise" oder "native rsvp.js-Unterstützung" fragen " und die Leute ihre eigene Versprechungsbibliothek zur Party mitbringen zu lassen, ist der einfachste Weg, diese Probleme zu lösen.

Ich verstehe was du meinst. Ich bin ein großer Nutzer und Unterstützer der Promises. Ich denke, es sollte in Betracht gezogen werden, den Standard durchzusetzen.
A+ Promises wurde als Anlaufpunkt für den ES6 gewählt. Ich habe das Polyfill vorgeschlagen, um die Unterstützung für die ES6-inkompatiblen Node-Versionen sicherzustellen (z. B. https://github.com/jakearchibald/es6-promise).

Es sollte in den Händen der anderen Promises-Bibliothek liegen, um mit den ES6-Promises kompatibel und mischbar zu sein.

BEARBEITEN:
Und es würde keinen Bruch in der aktuellen API geben oder übersehe ich etwas?

Die Promises/A+-Spezifikation unterscheidet sich stark von der ES6-Versprechensspezifikation, die sich wiederum von den Versprechensbibliotheken unterscheidet, die ich in den vorherigen Kommentaren aufgelistet habe. Obwohl es gut für mich wäre, wenn die unzähligen Versprechungsbibliotheken alle in ES6 konsolidiert würden, bezweifle ich, dass dies jemals passieren wird, denn das Schöne an Open Source ist, dass einige Leute, die Versprechen lieben, zusätzliche Funktionen wünschen und ihre eigenen Versprechen schreiben werden Bibliotheken.

Keine bahnbrechende Änderung für die aktuelle API, was ich denke, ist eine Möglichkeit, mongoose.set('Promise', require('bluebird')); oder so etwas zu sagen, also wäre es ein Opt-in und mpromise wäre die Standardeinstellung.

Ach so, sorry für diesen Fehler.
Ich habe mir die aktuelle Implementierung und die andere Promises-Bibliothek angesehen.

Ich denke, ich kann so etwas zum Laufen bringen:

mongoose.set('Promise', Promise);

mongoose.set('Promise', require('bluebird'));

mongoose.set('Promise', require('q').defer());

mongoose.set('Promise', require('when').defer());

// and so on...

Im Grunde genommen sollten Sie Mongoose also Ihr Versprechen der Wahl zeigen, das die Methoden resolve und reject hat.

Wäre das das, was Sie im Sinn hatten? Wenn ja, arbeite ich an einem Pull-Request.

BEARBEITEN:
Es fühlt sich extrem albern an, mongoose.set('Promise', Promise); zu schreiben. Ich denke, ES6 sollte der Standard sein, mit der Möglichkeit, die Bibliothek Ihrer Wahl zu verwenden (und mpromise, wenn ES6 Promises nicht verfügbar sind).

Sicher, ich würde Ihre Hilfe zu schätzen wissen. Das Knifflige wäre, 1) es mit Hooks zum Laufen zu bringen - siehe vkarpov15/kareem#2, und 2) es rückwärtskompatibel mit mpromise zu machen.

Bezüglich Q verwenden wir außerdem require('q').Promise , da dies die Q-Syntax ist, die der ES6-Spezifikation am nächsten kommt

Danke für deinen Beitrag, werde daran arbeiten. Bevorzugen Sie einen abgeschlossenen Pull-Request oder einen fortlaufenden PR?

Abgeschlossen ist besser, aber ich werde ausnahmslos einige Vorschläge haben. Lassen Sie mich wissen, wenn Sie nicht weiterkommen

+1 für diese Funktion. Ich möchte mit Bluebird verwenden

Tut mir leid, dass ich so drastisch bin – aber ein alternativer Ansatz wäre, die Unterstützung von Versprechungen insgesamt abzulehnen. Das würde jeden zum Schweigen bringen, der mit Versprechungen um die Unterstützung anderer Bibliotheken bittet.
Leute, die leistungsstarke Versprechungsbibliotheken wie Bluebird verwenden, können sie trotzdem weiter verwenden, da Sie eine Callback-API verfügbar machen und Bluebird dies trivialerweise zu einem Preis von 0 umschließen kann - tatsächlich stehen die Chancen gut, da Sie Versprechungen (wie Sie sagten) nicht kennen oder verwenden es wird sowieso langsamer und fehleranfälliger, sie manuell zu unterstützen.

@benjamingr 100% nicht einverstanden. Jetzt, da iojs und NodeJs in Node 3.0 zusammengeführt werden, wird es Unterstützung für ES6 Promises und Generators geben.

Die Abschaffung der Unterstützung wäre ein großer Rückschritt.

Das heißt, Promise.promisifyAll(require("mongoose")) erstellt einen schnellen (schneller als alle wahrscheinlichen manuellen Versuche) Wrapper für Mongoose, der die Standards beanstandet und die gesamte API umgibt, ohne dass Sie etwas dagegen tun müssen. Tatsächlich können Sie selbst Promise.promisifyAll für das exports-Objekt ausführen und Bluebird Promises und die duale Promises-Methode (save - saveAsync) kostenlos verfügbar machen und dann sagen, dass Sie eine Bluebird Promise-Schnittstelle verfügbar machen, ohne tatsächlich etwas tun zu müssen.

Während ich selbst Bluebird Promises verwende, denke ich, dass das Ganze durch einen Abschnitt in der Dokumentation behoben werden kann, anstatt Ihren Code durch Codierung auf zwei Schnittstellen zu verkomplizieren.

@albertorestifo , außer dass tatsächlich nichts gelöscht wird. Ich bin mir sehr wohl bewusst, was Versprechungen sind (über 1500 Punkte und 500 Antworten im Stapelüberlauf: P) und ich bin sogar für einige Teile ihrer Funktionsweise in io.js verantwortlich (wie https://github.com/ nodejs/io.js/issues/256).

Das ändert nichts an der Tatsache, dass ich glaube, da @vkarpov15 keine Versprechen verwendet, sollte er sie nicht in seiner Bibliothek unterstützen müssen _vor allem, da dies sowieso keinen Vorteil gegenüber der Verwendung von Versprechen mit sich bringt_. Sie können Promises genauso einfach mit Mongoose verwenden, selbst wenn es sie nicht bietet - Mongoose, das Unterstützung intern implementiert, ist wartungsärmer, wahrscheinlich langsamer und fehleranfälliger. @vkarpov15 kann weiter an der Rückruf-API arbeiten und versprechen, dass Benutzer Mongoose trotzdem mit Versprechen in einen einfachen Einzeiler verpacken können.

@benjamingr das setzt voraus, dass man eine externe Promise-Bibliothek verwendet. Ich bleibe bei dem in den Spezifikationen, und Sie wissen sehr gut, es hat keine Hülle.

Ich verstehe Ihren Punkt. Beides zu unterstützen, schafft ein riesiges Durcheinander. Ich persönlich verachte Rückrufe, also würde ich diese stattdessen fallen lassen. Vielleicht sollte es zwei getrennte Repositories geben, von denen eines Generatoren und Promises verwendet, das andere Callbacks verwendet. Beide würden die gleiche Struktur und die API so nah wie möglich beibehalten.

@benjamingr das setzt voraus, dass man eine externe Promise-Bibliothek verwendet. Ich bleibe bei dem in den Spezifikationen, und Sie wissen sehr gut, es hat keine Hülle.

Wenn Sie sich für eine langsame, schwieriger zu debuggende und weniger funktionsreiche Implementierung entscheiden, ist dies natürlich Ihre Wahl :P, aber wie hängt das mit dem Wrapper zusammen? Es ist ganz einfach, einen Wrapper zu schreiben, der dem von promisifyAll von bluebird ähnelt, indem native Promises* verwendet werden.

Wenn Sie eine Promise-aktivierte Version von Mongoose als separates Paket wünschen, können Sie dies folgendermaßen tun:

  • Schritt 1, öffnen Sie Ihren bevorzugten Editor oder einfach einen Editor, mit dem Sie irgendwie einverstanden sind.
  • Schritt 2, geben Sie module.exports = require("bluebird").promisifyAll(require("mongoose")) ein
  • Schritt 3, entsprechende package.json -Datei erstellen, in npm veröffentlichen
  • Schritt 4, Zehntausende von Downloads.

Nun, ich weiß, was Sie denken, "dies verwendet keine nativen Versprechungen", nun, Sie können immer noch jede Methode außer then und catch aus dem Versprechungsprototyp und all löschen race von Promise und enden mit der gleichen API - oder Sie können den Leuten einfach sagen, dass Sie native Promises exportieren - sie werden es nicht wissen, da es nur zwei Promises/A+-Implementierungen sind, Ich verspreche ;)

(*Es schnell zu schreiben ist auf Benutzerebene schwieriger, da es derzeit keine schnelle Möglichkeit gibt, Versprechungen zu erstellen, weshalb io.js wahrscheinlich irgendwann selbst eine Versprechungsfunktion exportieren wird - das heißt, indem Sie einen Versprechenskonstruktor nehmen, zu dem Sie ihn zwingen trotzdem langsam sein).

Das ist auf jeden Fall eine anständige Alternative. Ich würde Versprechen jedoch gerne intern halten, denn ob es Ihnen gefällt oder nicht, so werden Benutzer Mongoose verwenden, also könnten wir genauso gut eine solide Testabdeckung dafür haben, damit wir zeigen und sagen können: "So ist es Sie verwenden die Promise-Bibliothek X mit Mungo". Der Nachteil, wenn Sie Dinge in separate Module trennen, ist, dass es schwierig ist zu sagen "ok, diese Version von mongoose-promises funktioniert nur mit mongoose 3.8, diese funktioniert mit mongoose >= 4.1" und es für mongoose schwierig ist, zu vermeiden, einen übergreifenden Promises-Wrapper zu brechen .

Das ist auf jeden Fall eine anständige Alternative. Ich würde Versprechen jedoch gerne intern halten, denn ob es Ihnen gefällt oder nicht, so werden Benutzer Mongoose verwenden, also könnten wir genauso gut eine solide Testabdeckung dafür haben,

Warum möchten/brauchen Sie eine Testabdeckung dafür? Es hat keinen Sinn, Versprechungen selbst in Ihrem Code zu testen - die Bibliotheken haben bereits Tests - das ist wie das Testen des Moduls http , wenn Sie es verwenden.

und es ist schwierig für Mongoose, den Bruch einer übergreifenden Versprechungshülle zu vermeiden.

Bluebird macht etwas wirklich Einfaches - es findet Prototypen und fügt ihnen dann Methoden mit dem Suffix Async hinzu - das ist wirklich einfach und funktioniert in der Praxis gut - es ist ein Einzeiler mit den meisten Bibliotheken, einschließlich Mongoose, und es ist nicht kaputt gegangen sogar einmal für mich im vergangenen Jahr.

Ich bin mir nicht sicher, warum Sie eine Menge Stitching-Code verwalten möchten, der potenziell fehleranfällig ist. Die manuelle Unterstützung von zwei APIs mit ihren Randfällen klingt nach viel Arbeit, und Sie können Dinge nach und nach kaputt machen - Sie können "borgen" Sie sich den PromisifyAll-Code von bluebird und passen Sie ihn an, um mit anderen Promise-Bibliotheken zu arbeiten (es ist schließlich Open Source), aber ich würde es sicherlich nicht manuell tun.

"ok, diese Version von mongoose-promises funktioniert nur mit mongoose 3.8, diese funktioniert mit mongoose >= 4.1" und es ist schwierig für mongoose zu vermeiden, einen übergreifenden Promises-Wrapper zu brechen.

Könnten Sie mir ein Beispiel für eine bahnbrechende Änderung geben, die eintreten müsste, wenn die Versprechung automatisch erfolgt?

1) Ich möchte Dinge so testen, wie Benutzer sie verwenden.

2) Ich würde gerne faul sein und es vermeiden, aber so wie ich es verstehe, haben die meisten anderen Promise-Bibliotheken kein PromisifyAll-Äquivalent. Ich nehme an, dass dies der Grund ist, warum „Xpromise Feature Y unterstützen“ die beliebteste Mungo-Feature-Anfrage ist. Außerdem haben wir nicht die Absicht, die Versprechen von Bluebird umzuschreiben, sondern einfach dafür zu sorgen, dass Mungo-Funktionen ein Versprechen nativ zurückgeben.

3) Hängt von der Implementierung der Versprechen ab und wie Sie sie verwenden :)

1) Ich möchte Dinge so testen, wie Benutzer sie verwenden.

Was meinen Sie damit, die Art und Weise zu testen, wie Benutzer sie verwenden? Können Sie mir eine Analogie für Rückrufe zeigen?

2) Ich würde gerne faul sein und es vermeiden, aber so wie ich es verstehe, haben die meisten anderen Promise-Bibliotheken kein PromisifyAll-Äquivalent. Ich nehme an, dass dies der Grund ist, warum „Xpromise Feature Y unterstützen“ die beliebteste Mungo-Feature-Anfrage ist. Außerdem haben wir nicht die Absicht, die Versprechen von Bluebird umzuschreiben, sondern einfach dafür zu sorgen, dass Mungo-Funktionen ein Versprechen nativ zurückgeben.

Sie müssen nicht umschreiben, Sie können es nehmen - es ist nicht generisch, da eine generische Implementierung langsamer wäre.

Es ist auch keine Faulheit, ein weit verbreitetes Feature nicht manuell zu implementieren. Sind NodeJS faul, Express nicht in den Kern zu stecken? Sind TC39 faul, den Kern nicht zu unterstreichen? Indem Sie sich an eine Konvention (Callbacks) halten, geben Sie Benutzern die Möglichkeit, jedes beliebige Parallelitätsprimitiv zu verwenden.

3) Hängt von der Implementierung der Versprechen ab und wie Sie sie verwenden :)

Nun, Bluebirds Versprechen oder Q's oder When's - sie unterscheiden sich in der Implementierung, aber sie tun alle das Gleiche - also wählen Sie einfach eine aus, die Ihnen gefällt. Ich frage mich nur, wie es brechen würde.

Eine Sache fehlt mir in dieser Diskussion hier:

Wenn Mongoose ein Standardversprechen zurückgibt (standardmäßig bedeutet dies die native ES6-Implementierung), sollte es dann nicht mit jeder ES6-kompatiblen Promise-Bibliothek kompatibel sein? Ich kann Promise.all([model.query().exec(), ...]) ganz gut machen, ebenso wie den Bluebird, q, wenn es gleichwertig ist.

Warum also nicht Rückrufe und Standardversprechen zurückgeben (wie es jetzt der Fall ist, aber mpromise "loswerden") und den Benutzer seine bevorzugte Versprechungsbibliothek verwenden lassen? Oder übersehe ich hier etwas?

@albertorestifo Nun , einheimische Versprechungen sind im Moment langsam und es wird einige Zeit dauern, möglicherweise Jahre, bis sie die Parität mit Userland-Bibliotheken erreichen - also hauptsächlich das.

@benjamingr Sie machen einige gute Punkte. Der Hauptpunkt der Versprechungen von Mongoose besteht darin, Ihnen die Verwendung yield mit asynchronen Vorgängen von Mongoose ohne eine andere Bibliothek zu ermöglichen, weshalb wir unsere Versprechen für die absehbare Zukunft halten. Meiner Meinung nach sollte das in Zukunft wirklich Teil des Mongoose-Kerns sein.

Haben Q oder When eine Versprechungsfunktion?

Haben Q oder When eine Versprechungsfunktion?

Ja, praktisch jede weitverbreitete Versprechungsbibliothek, die ich kenne, bietet eine Art Versprechen an:

Hier ist wann: https://github.com/cujojs/when/blob/master/docs/api.md#nodeliftall
Hier ist Q: https://github.com/kriskowal/q/wiki/API-Reference#qnfbindnodefunc -args

Native Promises haben es noch nicht, aber es wird daran gearbeitet - sobald ein schneller Weg zum Erstellen von Promises (d. h. nicht der Promise-Konstruktor) existiert, wird NodeJS ihn wahrscheinlich im Kern für native Promises unterstützen (da es möglich ist). im Userland nicht _schnell_ erledigt).

Der Hauptpunkt der Versprechungen von Mongoose besteht darin, Ihnen die Verwendung von yield mit asynchronen Vorgängen von Mongoose ohne eine andere Bibliothek zu ermöglichen

Sie brauchen ohnehin eine Bibliothek, um yield sinnvoll mit Promises zu verwenden. Wenn Sie die 9 LoC, die einen Generator als asynchrone Funktion pumpen, selbst schreiben können, können Sie definitiv Promisify schreiben - und wenn Sie wie die meisten Benutzer sind, verwenden Sie dafür sowieso eine Bibliothek.

Ich sehe definitiv den Wunsch / die Notwendigkeit, Versprechen in Mongoose zuzulassen, sie sind der Weg nach vorne und wie die Sprache jetzt Parallelität ausführt, aber ich denke ehrlich, dass es schmerzhaft sein wird, es manuell Methode für Methode zu tun. Es kann von Vorteil sein, einfach zu demonstrieren, wie es mit Bibliotheken in einem Abschnitt „Verwenden mit Versprechungen“ oder „Verwenden mit Generatoren“ in der Dokumentation gemacht wird.

Die Sache ist, dass wir es bereits Methode für Methode getan haben, wir müssen nur den internen Promise-Wrapper ändern. Wie auch immer, wir können Versprechungen bis 5.0 nicht ganz aus dem Kern entfernen. Ich bin offen für die Idee, es abzulehnen, @benjamingr bringt einige gute Argumente vor, die ich genau prüfen muss, aber ich denke, der nächste Schritt wäre sowieso #2688.

Sie haben offensichtlich mehr Erfahrung mit Mongoose und, was noch wichtiger ist, mit seinen Benutzern - also verstehe ich diese Wahl. Vielen Dank, dass Sie mir zugehört haben.

Ich habe "its" eingegeben, aber mein iPhone hatte das Gefühl, es sollte es automatisch auf "it's" korrigieren, und GitHub war der Meinung, dass das Bearbeiten von Kommentaren kein interessanter Anwendungsfall ist. Entschuldigung für Doppelkommentar-Spam :)

Sie können Kommentare auf der Website bearbeiten, indem Sie auf den Stift rechts oben in Ihrem Kommentar klicken.

Ich bin immer offen für eine gute, herzliche Debatte, besonders eine, die mir etwas Neues beibringt :bier: Ich kann dich später anpingen, um mehr zu diskutieren :)

Die Zukunft gehört, so scheint es, einheimischen Versprechungen. Mongoose ist ein Industriestandard für Mongo-Operationen, es ist absolut gültig, sich auch auf Standardversprechen zu verlassen.

Standardversprechen werden zwangsläufig reifen und sich weiter verbreiten als jedes Framework. Ein bescheidenes +1 für die Verwendung.

@iliakan vielleicht in der Zukunft. Ich würde frühestens Mitte 2016 erwarten, dass native Promises zum „Standard“ werden, zu tief verwurzelt sind die diversen fragmentierten Promises-Bibliotheken und mit zu vielen subtilen Macken. Wie auch immer, Mongoose kann ohne eine massive rückwärts brechende Änderung nicht auf „standardmäßig nativ“ umschalten.

@ vkarpov15 sicher verstehe ich.

Was in der Zwischenzeit von Vorteil sein könnte - eine einfache Seite, die die wichtigsten Inkompatibilitäten zwischen mpromise und native Promises umreißt. Zumindest Dinge, die Sie mit mpromise nicht ausprobieren sollten ;)

Verstehe ich es richtig, dass es im Moment kein catch gibt, und das sind alle Einschränkungen?

Keine Ahnung, habe mich noch nicht wirklich mit der ES6-API beschäftigt. mpromise implementiert Promises/A+ und sonst nichts , was bedeutet, kein .catch(), keine langen Stack-Traces usw. usw. Grundsätzlich liegt alles, was nicht .then() ist, außerhalb des Umfangs der Implementierung von mpromise.

Im Allgemeinen implementiert etwas, das Promises/A+ implementiert, auch ES6-Versprechen aus einer übergeordneten Perspektive, aber das Gegenteil ist nicht der Fall. Promises/A+ ist sehr spezifisch in Bezug auf die Low-Level-Implementierungsdetails, zum Beispiel befolgt Bluebird Promises/A+ nicht genau, und ich bin mir nicht sicher, was andere gängige Promises-Bibliotheken betrifft, aber ich bin mir sicher, dass sie die Spezifikation nicht befolgen ihre eigenen einzigartigen Wege. Das wird es besonders schwierig machen.

Du meinst, kannst du jetzt Bluebird und native Promises verwenden?

Yup require('mongoose').Promise = global.Promise wird Mongoose dazu bringen, native Versprechungen zu verwenden. Sie sollten zwar jeden ES6-Versprechenskonstruktor verwenden können, aber im Moment testen wir nur mit nativen, Bluebird und Q

@vkarpov15 Das ist großartig! Ich danke dir sehr!

@vkarpov15 Vielen Dank! Gut gemacht!

Ja definitiv. Das ist wirklich cool! :)

@vkarpov15 Das ist wirklich nett

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen