6

According to MDN:

The executor function is executed immediately by the Promise implementation, passing resolve and reject functions

What were the actual reasons for this decision? Why promises are not lazy?

Jordan Running
  • 102,619
  • 17
  • 182
  • 182
Rax Wunter
  • 2,677
  • 3
  • 25
  • 32
  • 2
    Your question seems to apply that "lazy" promises would be superior in some way, but you neglect to specify what way that is. What would a lazy promises implementation look like to you? What would be the advantage? – Jordan Running Dec 06 '16 at 21:10
  • I thought, and considered, for a _long_ time, promise were lazy (were not evaluated until something .then them). I think it's just "simplier" this way – 131 Dec 06 '16 at 21:24
  • 1
    The point of an async interface is to **start** an operation now and then sometime in the future, when it completes, you can notify interested parties of its outcome. Thus, the point of the executor function is to enable you to start the async operation immediately (no point in waiting). – jfriend00 Dec 06 '16 at 21:30
  • 3
    There's a note on why promises aren't lazy in the [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) – 4castle Dec 06 '16 at 21:32
  • 2
    If you think lazy promises would be simpler, then you apparently want to use promises for something different than 99.99% of the programming population. Those aren't promises. That's a completely different paradigm. You could fairly trivially use promises in an implementation to do what you want (using promises to track the async operation with your own wrapper around it to decide when to actually fire the async operation), but that is not what a promise is or ever was and you are not correct that they would be better if designed that way. – jfriend00 Dec 08 '16 at 18:29

3 Answers3

5

What were the actual reasons for this decision?

The revealing Promise constructor with the callback was just an improvement over the older deferred pattern. The callback was never meant to provide choice over the evaluation time, it is supposed to provide a scope with error handling for the resolver functions.

Why promises are not lazy?

Because promises represent the asynchronous result values, nothing more. They're kept simple, without featuring lazyness (and representing the whole computation, with methods to start/repeat/etc). You can trivially get that by using a function that returns a promise instead.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I wouldn't say that simplicity here is good, because IMHO it doesn't solve anything. I'd like to see some advantages of immediate performing against lazy one – Rax Wunter Dec 06 '16 at 21:56
  • The most simple advantage: Because determining when to force the lazy value is hard. There are many possibilities, and none is universal. – Bergi Dec 06 '16 at 22:04
  • I think it's quite obvious to use `then` for it or any other additional method. Still not so strong advantage – Rax Wunter Dec 07 '16 at 08:09
  • What if `then` is called multiple times on the object? Execute the task multiple times? No, that's not how it is supposed to work. You're right, there's no strong advantage to making it lazy. – Bergi Dec 07 '16 at 08:29
  • Come on, it's more than doable. The same fulfilled mechanism + resolve only once – Rax Wunter Dec 07 '16 at 08:43
  • I never said it's not doable. I'm just saying it's not a promise any more. There are many libraries that implement `Task`s or hot/cold `Observable`s and other stuff, if you want these. – Bergi Dec 07 '16 at 08:46
  • @Bergi good answer to a difficult-to-answer question; objective and concise. – Mulan Dec 09 '16 at 14:30
1

Promises are meant to provide continuations, and actual state of standard Promise object proposes the following pattern:

function doStuff() {
    return new Promise((resolve, reject) => { // execution function
         // Do stuff here
    });
}

I would ask a question myself to understand why Promise's execution function is called immediatelly: where you would do the promised stuff?

Clearly, it's called immediatelly because you're making a promise that some stuff will be successfully or unsucessfully done, and that stuff should start to be processed as soon as you call the enclosing function to avoid confusion to the caller.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • Lazy operations in js are pretty straightforward. The thing is that you e.g cannot use bunch of such functions as a argument for Promise.all (in Bluebird implementation) – Rax Wunter Dec 06 '16 at 21:50
  • @RaxWunter Are you talking about generators? – Matías Fidemraizer Dec 06 '16 at 21:52
  • @Rax You wouldn't pass the function itself to `Promise.all`, you would pass the result of the function. – 4castle Dec 07 '16 at 00:30
  • Yes, I see your point, that for controlling sequence of execution it's more natural to use generators, but if Promises would be lazy we could use them as well. – Rax Wunter Dec 07 '16 at 08:20
  • @RaxWunter Yeah, in fact I'm not saying that it would be bad, but anyway, what would mean laziness in Promise pattern? Unless you call `then`, the operation isn't processed? – Matías Fidemraizer Dec 07 '16 at 14:07
  • Yep, just in my mind it gives more control over flow (when constructor does side effects it's a little bit strange) and I wanted to hear other opinions – Rax Wunter Dec 07 '16 at 14:11
  • @RaxWunter I would say: keep going. Don't get stuck with such details. Promises are simply an specification to implement continuations, usually with asynchronous operations. That's all. They don't look to add more capabilities to promises. – Matías Fidemraizer Dec 08 '16 at 21:28
1

The point of a promise is to have something to return from a function that callers can attach their callbacks to rather than pass them in. The constructor is a red herring to answer "why", as it exists solely to wrap old callback-style code in an imperfect world.

All JS functions are synchronous, even those returning a promise (es8's async is syntactic sugar).

The Promise constructor executor function exists to provide unified error handling. Consider:

function foo() {
  ""(); // throws TypeError
  return Promise(resolve => {
    ""(); // rejects promise with TypeError
  });
}

Callers would need both try{ foo().catch(failed); } catch(e) { failed(e); } = Sucks.

So put all your synchronous code inside the executor function to unify errors for your callers. That's what it's for, which I think is your real question.

"Lazy" execution would defeat the purpose of unifying error handling of all your code.

jib
  • 40,579
  • 17
  • 100
  • 158