Podczas testów odkryłem, że obietnice JavaScript są zawsze asynchroniczne niezależnie od tego, czy zawierają asynchroniczne funkcje w swoim łańcuchu.Dlaczego obietnice javascript obietnice są asynchroniczne podczas wywoływania tylko funkcji synchronicznych?
Oto kod, który pokazuje kolejność operacji w konsoli. Jeśli go uruchomisz, zobaczysz, że chociaż każda funkcja jest synchroniczna, dane wyjściowe pokazują, że oba połączenia aPromise()
są uruchamiane równolegle, a przed zakończeniem drugiego biegu dzieje się tak, jak przed rozpoczęciem drugiego.
function aPromise() {
return new Promise(function(resolve, reject) {
console.log("making promise A")
resolve(bPromise());
console.log("promise A resolved")
});
}
function bPromise() {
return new Promise(function(resolve, reject) {
console.log("making and resolving promise B")
resolve();
});
}
aPromise().then(function() {
console.log("finish run 1");
}).then(function() {
console.log("surprisingly this happens after run 2 finishes");
});
aPromise().then(function() {
console.log("finish run 2");
})
wyjścia do konsoli:
making promise A
making and resolving promise B
promise A resolved
making promise A
making and resolving promise B
promise A resolved
finish run 1
finish run 2
surprisingly this happens after run 2 finishes
Więc Dlaczego JavaScript obiecuje asynchroniczny Dzwoniąc tylko funkcje synchronicznych? Co dzieje się za kulisami, które prowadzą do tego zachowania?
P.S. Aby to lepiej zrozumieć, zaimplementowałem swój własny system obietnic i odkryłem, że sprawienie, by funkcje synchroniczne odbywały się w oczekiwanej kolejności było łatwe, ale ich równoległe wykonanie było czymś, co mogłem osiągnąć tylko przez ustawienie setTimeout() o kilku milisekundach na każdym kroku. rozwiązać (Domyślam się, że to nie jest to, co dzieje się z obietnicami wanilii i że są one faktycznie wielowątkowe).
To był mały problem dla jednego z moich programów, w którym przechodzę drzewo, stosując szereg funkcji dla każdego węzła i umieszczając funkcje w kolejce, jeśli ten węzeł ma już działającą funkcję asynchroniczną. Większość funkcji jest zsynchronizowana, więc kolejka jest rzadko używana, ale po przełączeniu z wywołań zwrotnych (piekło) na obietnice miałem problem, w którym koleje są używane prawie zawsze w wyniku obietnic nigdy nie działających synchronicznie. To nie jest duży problem, ale jest to trochę koszmarny debugowanie.
1 Rok Później EDIT
skończyło się na pisanie kodu, aby sobie z tym poradzić. Nie jest to zadziwiająco dokładne, ale użyłem go z powodzeniem, aby rozwiązać problem, który miałem.
var SyncPromise = function(fn) {
var syncable = this;
syncable.state = "pending";
syncable.value;
var wrappedFn = function(resolve, reject) {
var fakeResolve = function(val) {
syncable.value = val;
syncable.state = "fulfilled";
resolve(val);
}
fn(fakeResolve, reject);
}
var out = new Promise(wrappedFn);
out.syncable = syncable;
return out;
}
SyncPromise.resolved = function(result) {
return new SyncPromise(function(resolve) { resolve(result); });
}
SyncPromise.all = function(promises) {
for(var i = 0; i < promises.length; i++) {
if(promises[i].syncable && promises[i].syncable.state == "fulfilled") {
promises.splice(i, 1);
i--;
}
// else console.log("syncable not fulfilled" + promises[i].syncable.state)
}
if(promises.length == 0)
return SyncPromise.resolved();
else
return new SyncPromise(function(resolve) { Promise.all(promises).then(resolve); });
}
Promise.prototype.syncThen = function (nextFn) {
if(this.syncable && this.syncable.state == "fulfilled") {
//
if(nextFn instanceof Promise) {
return nextFn;
}
else if(typeof nextFn == "function") {
var val = this.syncable.value;
var out = nextFn(val);
return new SyncPromise(function(resolve) { resolve(out); });
}
else {
PINE.err("nextFn is not a function or promise", nextFn);
}
}
else {
// console.log("default promise");
return this.then(nextFn);
}
}
Ktoś inny może prawdopodobnie wykopać konkretnych rozmów, ale ogólna filozofia była to konsekwencja/przewidywalność jest cnotą w projektowaniu interfejsu. Niektóre wcześniejsze wdrożenia Promise nie zachowywały się w ten sposób, ale zmieniły się nastroje, gdy ludzie zostali ukąszeni przez nieoczekiwane błędy. Jest to * dużo * łatwiejsze do zrozumienia o obietnicach w ogóle, jeśli wiesz, że zawsze będą obsługiwane asynchronicznie. –
Czy wiesz, jakie rodzaje błędów? –
Szybkie spojrzenie na [** specyfikację **] (http://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects), a sformułowanie brzmi "Natychmiast ** będzie się zamykać ** zadanie, do którego należy zadzwonić ", najwcześniejszy moment, w który można wywołać zdarzenie, następuje natychmiast po zakończeniu bieżącej funkcji. 'nowa Promise (r => r()). then then (() => console.log (" yay ")); let i = 10; while (--i) console.log (i); 'logs 9..1 before the yay –