2015-03-06 8 views
32

Wie ich verstehe, ist ein Versprechen etwas, das auflösen() oder ablehnen(), aber ich war überrascht herauszufinden, dass der Code im Versprechen weiter ausgeführt wird, nachdem eine Auflösung oder Zurückweisung aufgerufen wurde.Warum setzt Javascript ES6 Promises die Ausführung nach einer Behebung fort?

Ich dachte, dass Auflösung oder Ablehnung eine async-freundliche Version von Exit oder Return, die alle sofortige Ausführung der Funktion stoppen würde.

Kann mir jemand erklären, den Gedanken hinter warum das folgende Beispiel zeigt manchmal die console.log nach einem resolve Aufruf:

var call = function() { 
    return new Promise(function(resolve, reject) { 
     resolve(); 
     console.log("Doing more stuff, should not be visible after a resolve!"); 
    }); 
}; 

call().then(function() { 
    console.log("resolved"); 
}); 

jsbin

+5

vernünftige Frage, aber dann wieder, JS führt nur eine Aussage nach der anderen, wie Sie es sagen zu. 'resolve()' ist keine JS-Steueranweisung, die magischerweise den Effekt von "return" haben würde, es ist nur ein Funktionsaufruf, und ja, die Ausführung wird danach fortgesetzt. –

+0

Das ist eine gute Frage, und selbst nachdem ich alle Antworten gelesen habe, bin ich mir nicht sicher über die besten Praktiken ... –

Antwort

61

JavaScript hat das Konzept von "run to completion". Wenn kein Fehler ausgelöst wird, wird eine Funktion ausgeführt, bis eine return Anweisung oder ihr Ende erreicht wird. Anderer Code außerhalb der Funktion kann dies nicht stören (es sei denn, erneut wird ein Fehler ausgelöst).

Wenn Sie möchten, dass Ihre resolve() initialiser Funktion verlassen, müssen Sie es prepend von return:

return new Promise(function(resolve, reject) { 
    return resolve(); 
    console.log("Not doing more stuff after a return statement"); 
}); 
+0

Hallo Felix - ich denke, das ist nur ein Teil der Geschichte - der andere Teil ist, dass 'resolve()' selbst eine asynchrone Funktion ist. Wie wir in der anderen (gelöschten) Antwort gesehen haben, glauben einige Leute, dass das Aufrufen von 'resolve' sofort Callbacks ausführt. – Alnitak

+2

@Alnitak 'resolve' selbst ist nicht asynchron, es ist vollständig synchron. Obwohl streng ES6 API verwendet wird, ist es nicht beobachtbar, ob es synchron oder asynchron ist. – Esailija

+0

@Esailija ok, vielleicht war ich unklar. Einige Leute glauben, dass das Aufrufen von 'resolve' dazu führt, dass registrierte Callbacks sofort aufgerufen werden, so dass sie Teil des aktuellen Call-Stacks sind. Das ist nicht wahr, stattdessen werden nur die Callbacks in die Warteschlange gestellt (und Sie haben Recht, es ist nicht asynchron, aber es macht einfach seine Sache und endet sofort) – Alnitak

14

die Rückrufe, die aufgerufen wird, wenn Sie resolve ein Versprechen, noch sind benötigt von der Spezifikation asynchron aufgerufen werden. Dies soll ein konsistentes Verhalten sicherstellen, wenn Versprechungen für eine Mischung aus synchronen und asynchronen Aktionen verwendet werden.

Deshalb, wenn Sie aufrufen resolve der Rückruf ist Warteschlange und Funktionsausführung fortgesetzt sofort mit jedem Code nach dem resolve() Anruf.

Nur wenn die JS-Ereignisschleife zurückgegeben wird, kann der Rückruf aus der Warteschlange entfernt und tatsächlich aufgerufen werden.

+0

Die Callback-Warteschlange ist in A + Specs oder in ES6 dokumentiert? – thefourtheye

+4

@thefourtheye: Die Event-Loop-Spezifikation ist jetzt Teil von [HTML5] (http://www.w3.org/TR/html5/webappapis.html#event-loops). ES6 definiert eine interne Methode namens [** 'EnqueueJob' **] (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-enqueuejob), die von [**' .then aufgerufen wird '**] (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.prototype.then). –

+0

@FelixKling Oh danke :) – thefourtheye