2016-04-20 10 views
7

Die Verschiebung der Ausführung von Funktionen, z. B. bei der benutzerdefinierten Ereignisbehandlung, ist ein gängiges Muster in JavaScript (siehe z. B. here). Es war einmal so, dass setTimeout(myFunc,0) der einzige Weg war, dies zu tun, aber mit Versprechungen gibt es jetzt eine Alternative: Promise.resolve().then(myFunc).Was bestimmt die Aufrufreihenfolge von Deferred Function mit Versprechungen oder setTimeout?

Ich hatte angenommen, dass diese das gleiche tun würden, aber während ich an einer Bibliothek arbeitete, die benutzerdefinierte Ereignisse enthielt, dachte ich, ich würde herausfinden, ob es einen Unterschied gab, also ließ ich den folgenden Block in den Knoten fallen:

var logfn=function(v){return function(){console.log(v)}}; 

setTimeout(logfn(1),0); 
Promise.resolve().then(logfn(2)); 
logfn(3)(); 

ich habe erwartet, auf der Konsole 3, 1, 2 zu sehen, aber stattdessen sah ich 3, 2, 1. Also mit anderen Worten, das Versprechen zu verwenden setTimeout nicht gleichwertig ist und an erster Stelle der Blöcke aus. Zumindest im Knoten.

Ich wiederholte den Test in Chrome und Firefox mit dem gleichen Ergebnis, aber in Edge kam es als 3, 1, 2. Ich würde auch erwarten, nicht-native Versprechen Bibliotheken SetTimeout unter der Haube zu verwenden, so würde herauskommen Gleich wie Edge.

Was bestimmt die Reihenfolge der aufgelösten Anrufe? Welches Modell wird von diesen verschiedenen Umgebungen verwendet, um die Ausführungsreihenfolge zu bestimmen? Ist eines der oben genannten Beispiele Standard oder Nicht-Standardverhalten?

PS Ich bin definitiv nicht vorschlagen, sich auf etwas davon zu verlassen konstant bleiben, ich bin nur neugierig.


Nach der Antwort weiter unten wies mich in der richtigen Richtung, und wie bereits erwähnt kurz im Kommentar unten, fand ich die vollständige Antwort in einer ausgezeichneten article by Jake Archibald (mit einem Beispiel fast identisch mit meinem Code oben), die ich obwohl ich hier hinzufügen würde, anstatt es in einem Kommentar begraben zu lassen.

+0

FWIW, ist nichts * garantiert * eine Bestellung für die asynchrone Ausführung. Sie sollten niemals versuchen, sich auf die Ausführungsreihenfolge zu verlassen. Das macht diese Frage zu einer interessanten Diskussion über Implementierungsdetails, aber praktisch umstritten. – deceze

+0

Vielleicht, aber ich neige dazu zu finden, dass meine Codierung verbessert, je mehr ich verstehe, wie alles zusammen hängt, auch wenn es indirekt ist. Nachdem ich die Antwort unten durchforstet habe, fand ich auch fast genau mein Beispiel oben plus eine vollständige Erklärung [hier] (https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/). Angesichts all dessen kann ich definitiv Fälle sehen, in denen das Aufschieben auf die Mikrotask- oder Makrotask-Warteschlange spezifisch angebracht sein könnte, obwohl man darauf achten muss, dass nichts kaputt geht, wenn nur Makrotasks verfügbar sind. –

Antwort

1

ll davon abhängt, wie resolve() intern umgesetzt wurde - beobachten Sie wahrscheinlich Unterschied zwischen setTimeout(fn, 0) und Edge-Implementierungen für setImmediate(fn)

Bitte beachten Sie die Artikel - http://www.mattgreer.org/articles/promises-in-wicked-detail/ und die Art und Weise, wie resolve Methode umgesetzt wurde.

function resolve(value) { 
    // force callback to be called in the next 
    // iteration of the event loop, giving 
    // callback a chance to be set by then() 
    setTimeout(function() { 
     callback(value); 
    }, 1); 
} 

als einige explenations können priority between setTimeout and setImmediate

Von Microsoft-Dokumentation zu finden - https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/dev-guide/performance/efficient-script-yielding/ und einen weiteren Link - setImmediate method

+2

Vielen Dank für den Artikellink und den Verweis auf 'setImmediate', das war neu für mich. Das Nachschlagen führte mich zum Polyfill [setImmediate] (https://github.com/YuzuJS/setImmediate), das zu dieser vorherigen Stackoverflow-Antwort auf den Unterschied zwischen der [mikrotask- und macrotask-Ereigniswarteschlange] führte (http: // stackoverflow.com/a/25933985/4098951), was zu erklären scheint, was passiert ist. Ich nehme an, Chrome und andere verwenden die Mikrotask-Ereigniswarteschlange, um Versprechungen zu implementieren, wobei "setTimeout" in der Makrotask-Warteschlange ausgeführt wird. Edge macht vielleicht keine solche Unterscheidung. –