In fase di test, ho riscontrato che le Promesse JavaScript sono sempre asincrone indipendentemente dal fatto che contengano o meno funzioni asincrone nella loro catena.Perché javascript promette asincrono quando si chiamano solo funzioni sincrone?
Ecco un codice che mostra l'ordine delle operazioni in console. Se lo esegui, vedrai che anche se tutte le funzioni sono sincrone, l'output mostra entrambe le chiamate aPromise()
eseguite in parallelo e "surprisingly this happens after run 2 finishes"
non prima che termini 2.
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");
})
uscita per console:
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
Quindi, Perché JavaScript promette asincrono quando si chiama solo le funzioni sincrone? Cosa sta succedendo dietro le quinte che porta a questo comportamento?
P.S. Per comprenderlo meglio ho implementato il mio sistema Promise e ho scoperto che rendere le funzioni sincrone nell'ordine previsto era facile, ma farle accadere in parallelo era qualcosa che avrei potuto ottenere solo impostando un setTimeout() di pochi millisecondi ad ogni risolvere (La mia ipotesi è che questo non è ciò che sta accadendo con le promesse di vaniglia e che in realtà sono in multi-thread).
Questo è stato un piccolo problema per uno dei miei programmi in cui sto attraversando un albero applicando una serie di funzioni a ciascun nodo e mettendo le funzioni in coda se quel nodo ha già una funzione asincrona in esecuzione. La maggior parte delle funzioni sono sincrone, quindi la coda viene usata raramente ma al passaggio da callback (diavolo) a Promises ho riscontrato un problema in cui le code vengono utilizzate quasi sempre a causa di Promises che non vengono mai eseguite in modo sincrono. Non è un problema enorme, ma è un po 'un incubo di debug.
1 anno dopo EDIT
ho finito per scrivere del codice per affrontare questo. Non è straordinariamente accurato, ma l'ho usato con successo per risolvere il problema che stavo vivendo.
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);
}
}
Qualcun altro può probabilmente scavare discussioni specifiche, ma la filosofia generale era che la coerenza/prevedibilità è una virtù nella progettazione dell'interfaccia. Alcune delle prime implementazioni di Promise non si comportavano così, ma il sentimento cambiava man mano che le persone venivano morse da errori imprevisti. È molto più facile ragionare sulle Promesse in generale se sai che verranno sempre gestite in modo asincrono. –
Sai che tipo di bug? –
Sguardo rapido su [** the spec **] (http://www.ecma-international.org/ecma-262/6.0/#sec-promise-objects) e la dicitura "immediatamente" verrà accodata ** un lavoro da chiamare ", la prima volta che una cosa _queque_ può richiamare è immediatamente dopo la fine della funzione corrente. 'new Promise (r => r()). then (() => console.log ('yay')); let i = 10; while (--i) console.log (i); 'logs 9..1 before the yay –