Warum verwenden Promise-Bibliotheken Ereignisschleifen?

8

In Anbetracht des folgenden JavaScript-Codes:

%Vor%

In den Versprechungsimplementierungen, die ich gesehen habe, würde provide.resolve () einfach eine Eigenschaft setzen, um anzuzeigen, dass die Verheißung aufgelöst wurde, und foo () würde später während einer Ereignisschleife aufgerufen werden, aber es scheint wie die provect.resolve ( ) hätte genügend Informationen, um verzögerte Funktionen wie foo () sofort aufzurufen.

Die Event-Loop-Methode scheint die Komplexität zu erhöhen und die Performance zu reduzieren. Warum wird sie also verwendet?

Während die meisten meiner Versprechen auf JavaScript basieren, liegt der Grund für meine Frage in der Umsetzung von Versprechen in sehr leistungsintensiven Fällen wie C ++ - Spielen. In diesem Fall frage ich mich, ob ich einige der Vorteile nutzen könnte Versprechen ohne den Overhead einer Ereignisschleife.

    
silentorb 03.05.2014, 17:45
quelle

3 Antworten

9

Alle vielversprechenden Implementierungen, zumindest gute, tun das.

Dies liegt daran, dass das Mischen von Synchronizität in eine asynchrone API , die Zalgo freigibt .

Die Tatsache, dass die Versprechen nicht sofort gelöst werden können und die Verzögerung manchmal bedeutet, dass die API konsistent ist. Andernfalls erhalten Sie undefiniertes Verhalten in der Reihenfolge der Ausführung.

%Vor%

Die Fakturierungsbibliotheken verzögern, bedeutet, dass die Reihenfolge der Ausführung des obigen Blocks garantiert ist. In gebrochenen Versprechen Implementierungen wie jQuery ändert sich die Reihenfolge abhängig davon, ob das Element aus dem Cache abgerufen wird oder nicht. Das ist gefährlich.

Eine nichtdeterministische Ausführungsreihenfolge ist sehr riskant und eine häufige Fehlerquelle. Die Promises / A + -Spezifikation wirft Sie hier in die Erfolgsspur.

    
Benjamin Gruenbaum 04.05.2014, 05:30
quelle
6

Ob promise.resolve() seine Fortsetzungen synchron oder asynchron ausführt, hängt wirklich von der Implementierung ab.

Außerdem ist die "Ereignisschleife" nicht der einzige Mechanismus, um einen anderen "Ausführungskontext" bereitzustellen. Es kann andere Mittel geben, zum Beispiel Threads oder Thread-Pools, oder man denke an GCD (Grand Central Dispatch, Versand-Lib), die Versandwarteschlangen bereitstellt.

Die Promises / A + Spec verlangt eindeutig, dass die Fortsetzung ( onFulfilled bzw. onRejected Handler) wird asynchron in Bezug auf den "Ausführungskontext" ausgeführt, in dem die Methode then aufgerufen wird.

  
  1. onFulfilled oder onRejected dürfen erst aufgerufen werden, wenn der Ausführungskontextstapel nur Plattformcode enthält. [3.1].
  2.   

Unter den Notizen können Sie lesen, was das eigentlich bedeutet:

  

Hier bedeutet "Plattformcode" Engine-, Environment- und Promise-Implementierungscode. In der Praxis stellt diese Anforderung sicher, dass onFulfilled und onRejected asynchron ausgeführt werden, nachdem die Ereignisschleife, die dann aufgerufen wird, und mit einem neuen Stack aufgerufen wird.

Hier wird jedes Ereignis in einem anderen "Ausführungskontext" ausgeführt, obwohl dies die gleiche Ereignisschleife und der gleiche "Thread" ist.

Da die Spezifikation Promises / A + für die Javascript-Umgebung geschrieben wurde, würde eine allgemeinere Spezifikation einfach erfordern, dass die Fortsetzung asynchron in Bezug auf den Aufrufer ausgeführt wird, der die Methode then aufruft.

Dafür gibt es gute Gründe!

Beispiel (Pseudocode):

%Vor%

Angenommen, der Handler (die Fortsetzung) wird im selben Thread wie die Call-Site ausgeführt, die Reihenfolge der Ausführung sollte so sein, dass die Konsole dies anzeigt:

%Vor%

Insbesondere wenn ein Versprechen bereits gelöst ist, neigen einige Implementierungen dazu, die Fortsetzung "sofort" (das heißt synchron ) im selben Ausführungskontext aufzurufen. Dies würde eindeutig gegen die oben genannte Regel verstoßen.

Der Grund für die Regel, die Folge immer asynchron aufzurufen ist, dass eine Aufruf-Site eine Garantie für die relative Reihenfolge der Ausführung von Handlern und Code nach dem then einschließlich der Fortsetzung haben muss Aussage in jedem Szenario. Das heißt, unabhängig davon, ob ein Versprechen bereits gelöst ist oder nicht, muss die Reihenfolge der Ausführung der Anweisungen gleich sein. Andernfalls funktionieren komplexere asynchrone Systeme möglicherweise nicht zuverlässig.

Eine weitere schlechte Design-Option für Implementierungen in anderen Sprachen, die mehrere simultane Ausführungskontexte haben - sagen wir eine Multithread-Umgebung (irrelevant in JavaScript, da nur ein Thread ausgeführt wird), ist, dass die Fortsetzung aufgerufen wird synchron in Bezug auf die Funktion resolve . Dies ist sogar problematisch, wenn die asynchrone Task in einem späteren Ereignisschleifenzyklus endet und somit die Fortsetzung tatsächlich asynchron in Bezug auf die Call-Site ausgeführt wird.

Wenn die resolve -Funktion jedoch von der asynchronen Task aufgerufen wird, wenn sie beendet ist, wird diese Task möglicherweise in einem privaten Ausführungskontext ausgeführt (etwa im "worker thread"). Dieser "Worker-Thread" ist normalerweise ein dedizierter und möglicherweise speziell konfigurierter Ausführungskontext - der dann resolve aufruft. Wenn diese resolve -Funktion synchron die Fortsetzung ausführt, wird die Fortsetzung im privaten Ausführungskontext der Aufgabe ausgeführt - was im Allgemeinen nicht erwünscht ist.

    
CouchDeveloper 10.05.2014 11:22
quelle
2

Bei Promises geht es um kooperatives Multitasking .

Die einzige Methode, um dies zu erreichen, ist die Nachrichtenbasierte Terminplanung.

Zeitgeber (normalerweise mit 0 Verzögerung) werden einfach verwendet, um den Task / die Nachricht in die Nachrichtenwarteschlange zu plazieren - yield-to-next-task-in-the-queue. So arbeitet die ganze Formation, bestehend aus kleinen Event-Handlern, und häufiger Sie - reibungsloser all diese Arbeit.

    
c-smile 04.05.2014 05:46
quelle