Why are javascript promises asynchronous when calling only synchronous functions?

佐手、 提交于 2019-11-27 20:17:53

The callback passed to a Promise constructor is always called synchronously, but the callbacks passed into then are always called asynchronously (you could use setTimeout with a delay of 0 in a userland implementation to achieve that).

Simplifying your example (and giving the anonymous function's names so I can refer to them) to:

Promise.resolve().then(function callbackA () {
  console.log("finish run 1");
}).then(function callbackB () {
  console.log("surprisingly this happens after run 2 finishes");
});

Promise.resolve().then(function callbackC () {
  console.log("finish run 2");
})

Still gives the output in the same order:

finish run 1
finish run 2
surprisingly this happens after run 2 finishes

Events happen in this order:

  1. The first promise is resolved (synchronously)
  2. callbackA is added to the event loop's queue
  3. The second promise is resolved
  4. callbackC is added to the event loop's queue
  5. There is nothing left to do so the event loop is accessed, callbackA is first in the queue so it is executed, it doesn't return a promise so the intermediate promise for callbackB is immediately resolved synchronously, which appends callbackB to the event loop's queue.
  6. There is nothing left to do so the event loop is accessed, callbackC is first in the queue so it is executed.
  7. There is nothing left to do so the event loop is accessed, callbackB is first in the queue so it is executed.

The easiest way I can think of to work around your problem is to use a library that has an Promise.prototype.isFulfilled function you can use to decide whether to call your second callback synchronously or not. For 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 this happens after run 2 finishes");
});

Promise.resolve()._SEPH_syncThen(function callbackC () {
  console.log("finish run 2");
})

This outputs:

finish run 1
surprisingly this happens after run 2 finishes
finish run 2

Your code is fine is you want your promises to run independently and let them execute in their own way, no matter each one complete first. As soon as your code is async, you cannot predict which one will be completed first (due to the async nature of the event loop).

However if you want to catch all your promises after they all completed, you should use Promise.all (which is the equivalent of $.when is jQuery). See:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!