Synchrone Versprechen Auflösung (bluebird vs. jQuery)
Entwickelt ich eine kleine lib für die Dynamics CRM REST/ODATA webservice (CrmRestKit). Die lib dependes auf jQuery und nutzt das Versprechen-Muster, repectivly das Versprechen-wie-Muster von jQuery.
Jetzt möchte ich port diese lib zu bluebird und entfernen Sie den jQuery-Abhängigkeit. Aber ich stehe vor einem problem, weil bluebird nicht unterstützen die synchrone Auflösung des promise-Objekte.
Einige Kontextinformationen:
Die API der CrmRestKit nimmt einen optionalen parameter, der definiert, ob der web-service-Aufruf durchgeführt werden sollten, sync oder async-Modus:
CrmRestKit.Create( 'Account', { Name: "foobar" }, false ).then( function ( data ) {
....
} );
Geben Sie "true" oder lassen Sie den letzten parameter, wird die Methode erstellt den Datensatz zu synchronisieren. - Modus.
Manchmal ist es notwendig, führen einen Betrieb im sync-Modus, zum Beispiel schreiben Sie JavaScript-code für Dynamics CRM, involed für das speichern-Ereignis einer form und in dieser event-handler, den Sie brauchen, um sync-operation für die Validierung (z.B. überprüfen, dass eine bestimmte Anzahl von Kind-Datensätze vorhanden sind, bei der richtigen Anzahl von Datensätzen vorhanden sein, brechen Sie die speichern-operation, und eine Fehlermeldung anzeigen).
Mein problem ist jetzt das folgende: bluebird unterstützt nicht die Auflösung im sync-Modus. Zum Beispiel wenn ich den folgenden, der "dann" - handler aufgerufen, der in async Mode:
function print( text ){
console.log( 'print -> %s', text );
return text;
}
///
///'Promise.cast' cast the given value to a trusted promise.
///
function getSomeTextSimpleCast( opt_text ){
var text = opt_text || 'Some fancy text-value';
return Promise.cast( text );
}
getSomeTextSimpleCast('first').then(print);
print('second');
Die Ausgabe ist folgende:
print -> second
print -> first
Ich würde erwarten, dass die "zweite" wird nach der "ersten", weil die Versprechen ist bereits gelöst mit einem Wert. Also ich würde davon ausgehen, dass eine dann-Ereignis-handler wird sofort aufgerufen , wenn angewandt, auf eine bereits beschlossene promise-Objekt.
Wenn ich das gleiche tun (verwenden Sie dann schon gelöst Versprechen) mit jQuery habe ich mein erwartetes Ergebnis:
function jQueryResolved( opt_text ){
var text = opt_text || 'jQuery-Test Value',
dfd = new $.Deferred();
dfd.resolve(text);
//return an already resolved promise
return dfd.promise();
}
jQueryResolved('third').then(print);
print('fourth');
Diese erzeugt die folgende Ausgabe:
print -> third
print -> fourth
Ist es eine Möglichkeit zu bluebird arbeiten in der gleichen Weise?
Update:
Der code war nur das problem veranschaulichen. Die Idee der lib ist: Unabhängig von der Ausführung-Modus (sync, async) der Anrufer wird es immer um ein promise-Objekt.
Hinsichtlich "... der Benutzer gefragt wird,... scheint nicht zu keinen Sinn": Wenn Sie zwei Methoden "CreateAsync" und "CreateSync" außerdem ist es bis zu dem Benutzer, zu entscheiden, wie die operation ausgeführt wird.
Sowieso mit der aktuellen Implementierung der default-Verhalten (der Letzte parameter ist optional), ist eine asynchrone Ausführung. Also 99% des Codes erfordert ein promise-Objekt, der optionale parameter ist nur für die 1% Fälle, in denen müssen Sie einfach einen sync-Ausführung. Desweiteren habe ich entwickelt, um die lib für mich und ich in 99,9999% der Fall der async-Modus, aber ich dachte, es ist schön, die option zu gehen die sync-Straße, wie Sie möchten.
Aber ich denkt, ich habe die Stelle ein sync-Methode sollte einfach wieder den Wert. Für die nächste Version (3.0) werde ich umsetzen "CreateSync" und "CreateAsync".
Vielen Dank für deinen input.
Update-2
Meine intension für den optionalen parameter war zu gewährleisten, besteht das Verhalten UND verhindern, dass Logik-Fehler. Davon aus, dass Ihr als Verbraucher meiner methode "GetCurrentUserRoles" verwendet lib. Also die Methode immer zurück ein Versprechen, das bedeutet, dass Sie verwenden müssen, wird der "then" - Methode, um code auszuführen, hängt vom Ergebnis. Also, wenn einige Schreibvorgänge code wie diesem, der ich Zustimmen, dass es Total falsch ist:
var currentUserRoels = null;
GetCurrentUserRoles().then(function(roles){
currentUserRoels = roles;
});
if( currentUserRoels.indexOf('foobar') === -1 ){
//...
}
Ich bin damit einverstanden, dass dieser code wird unterbrochen, wenn die Methode "GetCurrentUserRoles" änderungen aus dem sync async.
Aber ich verstehe, dass das ich nicht ein gutes design, weil die Verbraucher sollten jetzt, dass er sich mit einer async-Methode.
Ich möchte darauf hinweisen, dass der obige Kommentar ist von der Autorin von Bluebird.
Nein, es ist eine überladene Funktion (2 verschiedene Funktionen), bei denen der Anrufer wählt synchronity. Die API könnte genauso gut
CrmRestKit.CreateAsync
und CrmRestKit.CreateSync
statt CrmRestKit.Create({async: ?})
. Dies ist völlig Verschieden von einer Funktion, die vielleicht manchmal wissen, seine Rückkehr Wert synchron (z.B. 1st level cache-Datenbank-Aufruf)absolut nicht, sync-Funktionen muss wieder direkte Werte. Schlechteste API-immer wenn Sie verspricht mit synchronen Funktionen. Was jQuery macht, ist sehr falsch, denn es führt zu unvorhersehbaren Reihenfolge der Ausführung, wenn eine Funktion wirklich synchrone und asychrone - das ist, wenn der Anrufer nicht zu entscheiden. Auch ist es nicht "andere API" überhaupt Rückgabe von Werten aus einer synchronen Funktionen und verspricht von asynchronen. Suchen Sie im Knoten fs-API oder XMLHttpRequest-beispielsweise - weder Kräfte Sie Rückrufe oder verspricht, wenn Sie synchrone Aufrufe.
OP, ich denke, Sie haben genug Informationen, um entweder zu akzeptieren, die Antworten oder Rollen Sie Ihre eigenen, nicht wahr ?
InformationsquelleAutor thuld | 2014-01-15
Du musst angemeldet sein, um einen Kommentar abzugeben.
Kurze version: ich bekomme, warum Sie das tun wollen, aber die Antwort ist Nein.
Ich denke, die zugrunde liegende Frage ist, ob ein Versprechen abgeschlossen, sollten Sie sofort führen Sie einen Rückruf, wenn die Versprechen bereits abgeschlossen hat. Ich denke, der kann eine Menge von Gründen, dass dies passieren könnte - zum Beispiel einen asynchronen speichern-Prozedur, die speichert nur Daten, wenn änderungen vorgenommen wurden. Es kann in der Lage sein, um änderungen zu erkennen, die aus der client-Seite in einer synchronen Art und Weise ohne Umweg über eine externe Ressource, aber wenn änderungen erkannt werden, dann und nur dann wäre eine asynchrone operation erforderlich sein.
In anderen Umgebungen, die asynchrone Aufrufe, das Muster scheint zu sein, dass der Entwickler verantwortlich ist für das Verständnis, dass Ihre Arbeit könnte sofort vollständig (zum Beispiel, .NET framework ist die Implementierung des async-pattern nimmt dies). Dies ist nicht ein problem, der Rahmen, es ist so, wie es umgesetzt.
JavaScript Entwickler (und viele der Kommentatoren oben) scheinen zu haben eine andere Sicht auf diese, darauf hinzuweisen, dass, wenn etwas sein könnte asynchron, es muss immer asynchron. Ob dies "richtig" ist oder nicht, spielt keine Rolle - nach der Spezifikation fand ich bei https://promisesaplus.com/, Punkt 2.2.4 besagt, dass grundsätzlich keine callbacks aufgerufen werden können, bis Sie aus dem, was ich als "script-code" oder "Benutzer-code"; das heißt, die Spezifikation sagt eindeutig, dass, selbst wenn die Versprechen abgeschlossen ist, können Sie nicht aufrufen der callback sofort. Ich habe ein paar andere Orte, und entweder Sie sagen nichts über das Thema oder die Stimme mit der original-Quelle. Ich weiß nicht, ob https://promisesaplus.com/ könnte als eine endgültige Quelle der Informationen in dieser Hinsicht, aber keine anderen Quellen, die ich sah, nicht einverstanden mit ihm, und es scheint die meisten abgeschlossen.
Diese Einschränkung ist etwas willkürlich und ich ehrlich gesagt lieber die .NETTO-Perspektive auf diese ein. Ich überlasse es anderen zu entscheiden, wenn Sie halten es für "schlechten code" zu tun, etwas, das möglicherweise oder möglicherweise nicht synchron in einer Weise, dass sieht asynchron.
Ihre eigentliche Frage ist, ob oder nicht, Bluebird so konfiguriert werden kann, die nicht-JavaScript-Verhalten. Performance-Weise, es kann ein kleiner Vorteil zu tun, und in JavaScript-alles ist möglich, wenn Sie hart genug versuchen, aber als das Promise-Objekt wird mehr allgegenwärtig auf allen Plattformen, die Sie sehen eine Verschiebung zu mit es wie eine native Komponente anstelle von benutzerdefinierten geschriebenen polyfills oder Bibliotheken. Als solche, wie auch immer die Antwort ist heute, Nacharbeiten ein Versprechen in Bluebird verursachen Sie Probleme in der Zukunft, und der code sollte wohl nicht geschrieben werden, abhängen oder eine sofortige Auflösung des ein Versprechen.
InformationsquelleAutor Joe Friesenhan
Man könnte denken, dies ist ein problem, denn es gibt keine Möglichkeit zu haben
und haben
getSomeText
"first"
gedruckt, bevor die"second"
wenn die Auflösung ist synchron.Aber ich denke du hast ein Logik problem.
Wenn Ihr
getSomeText
- Funktion kann synchron oder asynchron, je nach Kontext, dann sollte es keinen Einfluss auf die Reihenfolge der Ausführung. Verwenden Sie verspricht, um sicherzustellen, es ist immer das gleiche. Eine variable Reihenfolge der Ausführung würde wahrscheinlich zu einem Fehler in der Anwendung.Verwenden
In beiden Fällen (synchron mit
cast
oder asynchrone Auflösung), haben Sie die richtige Ausführung bestellen.Beachten Sie, dass eine Funktion manchmal synchron und manchmal auch gar nicht seltsam oder unwahrscheinlich Fall (man denke etwa cache-handling, oder pooling). Sie müssen nur angenommen, es ist asynchron, und alles wird immer fein.
Aber Fragen Sie den Benutzer der API zu präzise mit einem boolean-argument, wenn er möchte, dass die operation asynchron scheint nicht zu Sinn, wenn Sie nicht verlassen den Bereich von JavaScript (D. H., wenn Sie nicht einige native-code).
Der wirklich wichtige Punkt ist, dass mit einem code, der je ein Versprechen wird sofort ausgeführt wird, ist ein bug. Nicht mit synchroner Auflösung der Versprechen, die Ihnen helfen zu vermeiden, diese Art von Fehler.
Das problem mit .dann (und callback-Aufruf verzögert, bis zum nächsten Programmzyklus) ist, dass es fügt erheblichen Verzögerung in den meisten Implementierungen, Versprechungen nicht akzeptabel Lösung für Zeitkritische Prozesse, wie Animationen. Zum Beispiel, wenn Sie so etwas wie:
spinUp.then(rotateXtimes).then(slowDown)
erhalten Sie spürbare animation bricht, während die synchrone Auflösung mit einfacher Rückrufe wiespinUp(function(){rotateXtimes(function(){slowDown(done)})})
nicht einführen ohne Verzögerungen.wirklich wichtige Punkt ist, dass mit einem code, der je ein Versprechen wird sofort ausgeführt wird, ist ein Fehler." Es ist nicht immer ein bug. Es gibt Anwendungsfälle für die synchrone Auflösung/Abwicklung von Rückrufen, wenn die Daten bereits vorhanden und man möchte es synchron, aber Sie wollen die Wiederverwendung der vorhandenen async-fähigen code-Pfad. (zum Beispiel meinen aktuellen Gebrauch-Fall hier: github.com/stacktracejs/stacktrace.js/issues/188)
InformationsquelleAutor Denys Séguret
Dem Punkt, Versprechungen zu machen asynchrone code einfacher, d.h. näher zu dem, was Sie fühlen, wenn Sie mit synchrone code.
Bist du mit synchronen code. Machen Sie es nicht komplizierter.
Und das sollte das Ende sein.
Wenn Sie möchten, um die gleiche asynchrone Schnittstelle, obwohl Ihr code ist synchron, dann haben Sie es zu tun den ganzen Weg.
then
bekommt den code aus dem normalen Ausführung fließen, denn es soll asynchron. Bluebird hat es den richtigen Weg gibt. Eine einfache Erklärung von, was es tut:Beachten, dass bluebird nicht wirklich tun, es ist nur, um Ihnen ein einfaches Beispiel.
Probieren Sie es aus!
Dieser wird Folgendes ausgegeben:
Margaine, um ehrlich Zu sein ich lieber den Weg jQuery behandelt 'dann' synchron. Ich benutze es zum Beispiel das bauen einer dynamischen Kette von Ereignissen, wobei die nachfolgenden Funktionen stützen sich auf die Ergebnisse aus der vorangegangenen, die auch variieren basierend auf bestimmten Kriterien, und werden durch eine gemeinsame fehlschlagen und die done-Funktion. Die alternative ohne verspricht, führt in der Regel zu einer komplizierten Reihe von callback-Funktionen, die sind sehr schwer zu Folgen. Nicht klopfen bb hier, ich überlege, die Migration für die performance-Vorteile. Ich verstehe einfach nicht, wie ich dies erreichen, sonst wenn dann immer async.
Was redest du da? Wenn Sie sync-Funktionen nicht nutzen verspricht - wenn Sie async jQuery-Funktionen deferreds erstellen race conditions durch laufen asynchron manchmal auf dem anderen hand Bluebird läuft immer den gleichen Weg unabhängig von der Rasse.
Es ist ein wenig schwer auszudrücken, ohne dass ein code-Beispiel, und ich will nicht zu entführen den thread. Im Grunde genommen mehrere voneinander abhängige "dann" - Funktionen gegen ein Versprechen, das zu beheben, sobald die Kette der Funktionen angeordnet sind. wie myPromise.dann(NOR).dann(dynamicFunc).dann(functionD).fail(failFunction).fertig(doneFunction), wo dynamicFunc kann entweder functionB oder functionC. dann einfach anrufen myPromise.beheben({data}) beginnen. Jede Funktion definiert eine latente und gibt ein Versprechen (Ausnahme gemacht und scheitern), dann löst oder lehnt die latente entweder übergibt die Daten an die nachfolgende Funktion oder Aufrufe schlagen fehl.
BTW können Sie erklären, den "race-condition" - Sache? Vielleicht mit einem Beispiel? Ich kann nicht scheinen zu finden, viel info, speziell über, warum das passieren könnte. Wenn Sie wissen, jeder gute Ressourcen, die ich lieben würde, zu sehen.
InformationsquelleAutor Florian Margaine
Gibt es einige gute Antworten hier schon, aber in der Summe den Kern der Sache sehr kurz und bündig:
Ein Versprechen (oder anderen asynchronen API), die manchmal asynchron und manchmal synchron ist eine schlechte Sache.
Können Sie denken, es ist in Ordnung, weil der erste Aufruf der API akzeptiert einen booleschen zum wechseln zwischen sync/async. Was aber, wenn begraben in einigen wrapper-code und die person, die mit , dass code nicht wissen, über diese Machenschaften? Sie haben soeben mit einigen unpreditable Verhalten durch keine Störung von Ihren selbst.
The bottom line: versuchen Sie nicht, dies zu tun. Wenn Sie möchten, synchrones Verhalten, nicht wieder ein Versprechen.
Mit, dass, ich lasse Sie mit diesem Zitat aus You Don ' T Know JS:
InformationsquelleAutor JLRishe
Was über diesen Fall, auch CrmFetchKit Verwandte, die in der neuesten version benutzt Bluebird. Ich habe ein Upgrade von version 1.9, basierend auf jQuery. Noch die alte app-code, der verwendet CrmFetchKit hat Methoden die Prototypen von denen ich nicht können oder nicht ändern.
Vorhandenen App-Code
Alten CrmFetchKit Umsetzung (eine angepasste version von fetch())
Neuen CrmFetchKit Umsetzung
Mein problem ist, dass die alte version hatte der dfd.lösen (...), wo ich war in der Lage, übergeben Sie eine beliebige Anzahl von Parameter, die ich brauche.
Die neue Implementierung nur die Renditen, die übergeordneten scheint, rufen Sie den Rückruf, ich kann nicht direkt aufrufen.
Ging ich und machte eine benutzerdefinierte version von fetch() in der neuen Implementierung
Aber das problem ist, dass der callback wird aufgerufen, zwei mal, einmal wenn ich es explizit tun und zweitens durch das framework, sondern es geht es einen parameter nur. Trick und "sagen" nicht zu nennen, nichts, weil ich es explizit tun, die ich versuche zu nennen .Abbrechen (), aber es wird ignoriert. Ich habe verstanden, warum, aber noch wie machst du die "dfd.resolve(result.Entitäten, das Ergebnis.totalRecordCount);" in der neuen version ohne änderungen-Prototypen in der app verwendet diese Bibliothek ?
result
Objekt und ändern Sie dann die callback-Funktion bereitgestellt, um die.then()
nur annehmenresult
- Objekt als argument.Danke, scheint dies der einzige Weg ist. Ich Tat, ändern Sie die App-code zu akzeptieren, die ein Objekt als parameter und extrahieren von dort den anderen beiden. Ich denke, das ist eine wichtige änderung bei der Aktualisierung der Bibliothek zu einer neuen version.
InformationsquelleAutor Nicolas
Können Sie in der Tat tun, ja.
Ändern Sie die
bluebird.js
- Datei (für npm:node_modules/bluebird/js/release/bluebird.js
), mit folgender änderung:Weitere Infos finden Sie hier: https://github.com/stacktracejs/stacktrace.js/issues/188
InformationsquelleAutor Venryx