Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should the factory be run in a new event loop turn? #20

Open
domenic opened this issue Feb 15, 2013 · 3 comments
Open

Should the factory be run in a new event loop turn? #20

domenic opened this issue Feb 15, 2013 · 3 comments

Comments

@domenic
Copy link
Member

domenic commented Feb 15, 2013

In #18, I propose letting the factory run in a new event loop turn. This parallels assimilation, which must be done in the next turn for integrity reasons. Nevertheless, it's not necessary for the constructor; we could have assimilation do a next-turn call to the constructor.

Note that this doesn't prevent building deferreds from the promise constructor, but it does make them more awkward:

function defer() {
  var resolve;
  var reject;

  var promise = new Promise(function (resolveArg, rejectArg) {
    resolve = resolveArg;
    reject = rejectArg;
  });

  return {
    promise: promise,
    resolve: function (x) {
      nextTick(function () { resolve(x); });
    },
    reject: function (reason) {
      nextTick(function () { reject(reason); });
    }
  };
}
@juandopazo
Copy link

In YUI we went for a synchronous initialization function. I don't think it's necessary for it to be async and there are cases in which we want to pass around the resolve and reject functions.

@erights
Copy link

erights commented Feb 16, 2013

Hi @domenic, after our last conversation (also with @kriskowal ) I looked back at some of my uses of Q.promise and realized that making the factory invocation async would break important use cases. In particular, I do the following a lot:

var r1;
var p1 = Q.promise( (resolve, reject) => { r1 = resolve; } );
// use both r1 and p1.

If the factory were invoked asynchronously, then r1 will not yet have been initialized following the call.

OTOH, now that I'm writing this, perhaps async here is better after all, for a bizarre reason. I find myself using the above pattern and not putting the use-of-r1 code in the factory when that code needs access to both r1 and p1. But if the factory is invoked asynchronously:

var p1 = Q.promise( (resolve, reject) => {
    // use both resolve and p1
});

is perfectly fine. In fact it's better. Hmmm.

@erights
Copy link

erights commented Feb 16, 2013

It is worth noting that assimilation essentially subsumes async promise construction. If Q.promise invokes the factory asynchronously, and if it ignores any exceptions thrown by the factory function, then the following two bits of code are equivalent. Shown first in ES5, then in ES6:

var p1 = Q.promise( function(resolve, reject) { ... } );
vs
var p1 = Q( {then: function(resolve, reject) { ... }} );

var p1 = Q.promise( (resolve, reject) => { ... } );
vs
var p1 = Q( {then(resolve, reject) { ... }} );

Note that in both cases, assimilation is less verbose.

This redundancy raises a few options:

  • Drop promise construction completely, and depend only on assimilation.
  • Have Q.promise remain synchronous, since assimilation covers the async case better.
  • undeprecate Q.defer and deprecate Q.promise. If the only purpose is the sync case not covered by assimilation, Q.defer handles that case by itself better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants