2016-03-19 8 views
3

Ich führe die Code-Probe auf meinem Rechner (mit Knoten 5.8.0 installiert) und bekomme das nächste Ergebnis (siehe nach dem Codebeispiel).Warum das Promise.all (Array) nicht sofort aufgelöst?

Codebeispiel:

'use strict' 

var p1 = Promise.resolve(); 
var p2 = Promise.resolve(); 

var p12 = Promise.all([p1, p2]); 

var cb = function() { 
    console.log(p12); 
} 

setTimeout(cb, 0); 

console.log(p1); 
console.log(p2); 
console.log(p12); 

Ergebnis:

Versprechen {undefined}
Versprechen {undefined}
Versprechen {<pending>}
Versprechen {[undefined, undefined]}

Warum ist es so, dass p12 nicht unmittelbar nach p1 und p2 aufgelöst wird (was p1 und p1 am Anfang des Programms aufgelöst hat), und warum wurde 'timeouted' p12 aufgelöst? Gibt es eine gewisse Zeit für Promise.Alle (Array) wird gelöst?

+0

Versuchen Sie Ihre Resolve zu ändern: 'Promise.resolve (true);' – CodingGorilla

Antwort

4

Gemäß der Verheißungsspezifikation wird ein Versprechungs- oder Ablehnungs-Handler immer asynchron aufgerufen, nachdem die Ereignisschleife ihren aktuellen Zyklus beendet hat. Daher wird p12 nicht sofort aufgelöst, obwohl die Argumente dafür alle aufgelöste Versprechen sind. Daher wird es erst kurz nach Beendigung dieser Ereignisschleife aufgelöst. Dies erklärt, warum Ihre erste Aussage:

console.log(p12); 

zeigt, dass das Versprechen noch „offen“. Es ist aktuell .then() Handler (falls vorhanden) wurden noch nicht aufgerufen. Sobald jedoch der aktuelle Code-Thread fertig ausgeführt ist und die Steuerung zum nächsten Event in der Event-Queue zurückkehrt, wird das Versprechen gelöst und Ihr setTimeout() sieht es dann als aufgelöst an. Diese


ist für Anrufer aus Konsistenzgründen getan, so dass .then() Handler konsequent auf eine asynchrone Weise aufgerufen werden, egal, ob das Versprechen wurde bereits gelöst oder ist noch nicht gelöst. Dadurch kann der aufrufende Code immer konsistent codieren, ohne sich darüber Gedanken machen zu müssen, ob das Versprechen bereits gelöst sein könnte. In allen Fällen werden .then() Handler aufgerufen, nachdem der aktuelle Stack abgewickelt und beendet ist.

Vom Promises/A+ specification:

onFulfilled oder onRejected darf nicht aufgerufen werden, bis die Ausführung Kontextstapel nur Plattform-Code enthält.

Hier bedeutet "Plattform-Code" Engine, Umgebung und Versprechen Implementierungscode. In der Praxis stellt diese Anforderung sicher, dass onFulfilled und onRejected asynchron ausgeführt werden, nach dem Ereignis Schleife drehen in der dann aufgerufen wird, und mit einem frischen Stapel. Dies kann entweder mit einem "Makro-Task" -Mechanismus wie setTimeout oder setImmediate oder mit einem "Mikro-Task" -Mechanismus wie MutationObserver oder process.nextTick implementiert werden. Da die Promise-Implementierung als Plattformcode betrachtet wird, kann sie selbst eine Task-Scheduling-Warteschlange oder "Trampolin" enthalten, in der die Handler aufgerufen werden.

Also das Ergebnis von all dem ist, dass Versprechen immer asynchron zu lösen, nachdem der aktuelle Thread der Ausführung beendet ist. Obwohl die internen Details etwas komplizierter sind (vielleicht mit Mikro-Aufgaben), können Sie logisch denken, dass ein Versprechen dadurch gelöst wird, dass eine Nachricht in die Ereigniswarteschlange gestellt wird, auf die jetzt gewartet werden soll. Und immer wenn die Ereigniswarteschlange beendet wird, was gerade ausgeführt wird, und dann die Versprechungen Handler ausgeführt werden, werden sie ausgeführt.

+0

Also ".all (array)" muss ähnlich verstanden werden wie ".then()" handler (nicht zu ".resolve()" Methode) ... Macht Sinn. Vielen Dank. @ jfriend00 – olegzhermal