Why are javascript promises asynchronous when calling only synchronous functions? -
in testing i've found javascript promises always asynchronous regardless of whether or not contain asynchronous functions in chain.
here code shows order of operations in console. if run see though every function synchronous output shows both of apromise()
calls being run in parallel, , "surprisingly happens after run 2 finishes"
not happening before run 2 finishes.
function apromise() { return new promise(function(resolve, reject) { console.log("making promise a") resolve(bpromise()); console.log("promise resolved") }); } function bpromise() { return new promise(function(resolve, reject) { console.log("making , resolving promise b") resolve(); }); } apromise().then(function() { console.log("finish run 1"); }).then(function() { console.log("surprisingly happens after run 2 finishes"); }); apromise().then(function() { console.log("finish run 2"); })
output console:
making promise making , resolving promise b promise resolved making promise making , resolving promise b promise resolved finish run 1 finish run 2 surprisingly happens after run 2 finishes
so, why javascript promises asynchronous when calling synchronous functions? happening behind scenes leads behavior?
p.s. in order better understand implemented own promise system , found making synchronous functions happen in expected order easy making them happen in parallel accomplish putting settimeout() of few milliseconds @ every resolve (my guess not what's happening vanilla promises , being multi threaded).
this has been small problem 1 of programs i'm traversing tree applying array of functions each node , putting functions in queue if node has asynchronous function running. of functions synchronous queue used upon switching on callbacks (hell) promises i've been having issue queues used result of promises never running synchronously. it's not huge problem bit of debugging nightmare.
1 year later edit
i ended writing code deal this. it's not amazingly thorough, i've used success solve issue having.
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 = 0; < 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 not function or promise", nextfn); } } else { // console.log("default promise"); return this.then(nextfn); } }
the callback passed promise constructor called synchronously, callbacks passed then
called asynchronously (you use settimeout
delay of 0
in userland implementation achieve that).
simplifying example (and giving anonymous function's names can refer them) to:
promise.resolve().then(function callbacka () { console.log("finish run 1"); }).then(function callbackb () { console.log("surprisingly happens after run 2 finishes"); }); promise.resolve().then(function callbackc () { console.log("finish run 2"); })
still gives output in same order:
finish run 1 finish run 2 surprisingly happens after run 2 finishes
events happen in order:
- the first promise resolved (synchronously)
- callbacka added event loop's queue
- the second promise resolved
- callbackc added event loop's queue
- there nothing left event loop accessed, callbacka first in queue executed, doesn't return promise intermediate promise callbackb resolved synchronously, appends callbackb event loop's queue.
- there nothing left event loop accessed, callbackc first in queue executed.
- there nothing left event loop accessed, callbackb first in queue executed.
the easiest way can think of work around problem use library has promise.prototype.isfulfilled function can use decide whether call second callback synchronously or not. example:
var promise = require( 'bluebird' ); promise.prototype._seph_syncthen = function ( callback ) { return ( this.ispending() ? this.then( callback ) : promise.resolve( callback( this.value() ) ) ); } promise.resolve()._seph_syncthen(function callbacka () { console.log("finish run 1"); })._seph_syncthen(function callbackb () { console.log("surprisingly happens after run 2 finishes"); }); promise.resolve()._seph_syncthen(function callbackc () { console.log("finish run 2"); })
this outputs:
finish run 1 surprisingly happens after run 2 finishes finish run 2
Comments
Post a Comment