promises-aplus / promises-spec

An open standard for sound, interoperable JavaScript promises—by implementers, for implementers.
https://promisesaplus.com/
Creative Commons Zero v1.0 Universal
1.84k stars 164 forks source link

Boolean flag passed to .then to allow for synchronicity #110

Closed ckknight closed 11 years ago

ckknight commented 11 years ago

Though the spec dictates that .then must return a thenable in an asynchronous way, even if the promise is already fulfilled, it would be nice to have the option to opt-in for potentially-synchronous execution.

Use case:

var owns = Object.prototype.hasOwnProperty;
var cache = {}
function calculate(key) {
  if (owns.call(cache, key)) {
    return MyPromise.fromResult(cache[key]); // already marked as fulfilled
  } else {
    var promise = new MyPromise();
    doSomeCalculation(key, function (err, result) {
      if (err) {
        promise.reject(err);
      } else {
        promise.fulfill(result);
      }
    });
    return promise;
  }
}

calculate("myKey").then(onFulfilled, onRejected, true); // passing in true allows the promise library to opt-in for synchronous execution if already fulfilled/rejected.

If a Promises/A+-compliant library does not support the boolean, then it could just be ignored and always run asynchronously.

Since this is opt-in on the user-facing side, the onus is on the client of the promise library to be aware of the consequences.

ralphholzmann commented 11 years ago

I'm not seeing the benefit of this. Why do you need a promise to resolve sync vs async? :thumbsdown:

ckknight commented 11 years ago

In the case where you'd like to run code synchronously if possible, but do things asynchronously if that's not the case. If I can execute my code in the same event loop and not have to keep unnecessary objects around for potentially many cycles, it can be beneficial.

For example, if in the browser where setTimeout must be used and not in Chrome (which allows for sub-17 ms time), then having a promise tree that could be all executed right away could give results in <= 1 ms rather than potentially several hundred ms.

The reason to force the asynchronicity is for the developer's benefit in being able to use the promise after .then is called, but before its callbacks are executed. If the developer doesn't need this and opts in for sync-mode, it seems like it should be allowed rather than forcing the developer to wait.

domenic commented 11 years ago

We have no interest in synchronous promise settling. A Promises/A+ promise should guarantee asynchronous behavior; if you use any library that claims conformance, you should be safe from the side effects that come with synchronicity. If a developer feels these guarantees are not worthwhile, then he should use a non-Promises/A+ compliant library.

To address

For example, if in the browser where setTimeout must be used and not in Chrome (which allows for sub-17 ms time), then having a promise tree that could be all executed right away could give results in <= 1 ms rather than potentially several hundred ms.

This is wrong on several levels. First, setTimeout's minimum time is 4 ms in all browsers, not 17. Second, every browser from IE6 onward has a way of circumventing that and getting lower timing. Finally, there is nothing stopping a tree of promises from collapsing into a single tick; many popular promise libraries do this. As long as the invariants are obeyed with regard to when onFulfilled or onRejected are called, you can settle as many promises in a single tick as you wish. For example, given

var p2 = p.then(f1).then(f2).then(f3);

there is nothing stopping f1, f2, and f3 all from being called in a single tick, as long as it is the tick after the calls to then.

ckknight commented 11 years ago

Where is the harm in allowing for a developer to opt-in with a boolean flag for potentially synchronous results?

Also, any conforming library would not have to observe the flag and keep running asynchronously as-is. This is only for the case if the library observes the flag and the developer opts-in. If either side ignores it, there is no inherent harm.

You say "we" have no interest, but who is "we" in this case? I'm certainly interested in having this capability.

juandopazo commented 11 years ago

Basically there was consensus when asynchronicity was discussed before version 1.0 of the spec. And I think there is still consensus. You can read the rationale in previous discussions.

However, there is nothing preventing you from implementing this in your system as long as you do it in another method not called then.

ForbesLindesay commented 11 years ago

I'm hugely in favour of a method called something like maybeSync(onFulfilled,onRejected) that has this semantics, but I too don't think it should be in .then

ForbesLindesay commented 11 years ago

The biggest advantage I actually see to having a synchronous alternative to .then is in building algorithms that support both synchronous and asynchronous operation. Not for performance, but for simplicity. I have a bit of software that does a series of file resolutions to look for a file in all the possible locations. Sometimes I don't need it to be asynchronous, sometimes I do.