5 ms·
This was a weird blog post to read. I think I agree on all of your points (Promises should be lazy[-ish], cancellable and optionally synchronous) but disagree o
by xori 9y ago
This was a weird blog post to read. I think I agree on all of your points (Promises should be lazy[-ish], cancellable and optionally synchronous) but disagree on all of your proposed solutions.
I do think `p = new Promise(fn);` shouldn't kick off the `fn` immediately. But that it should start right away in the next event loop. I haven't had issues with creating promise getters for repeatable calls. And think it organizes the business code away from the low level code.
I don't see a problem with the original Promise.cancel() you proposed or how your lazy promises makes canceling them any easier.
And don't we have `await` for the synchronous problem?
console.log(await Promise.resolve('hello'));
console.log('world')
// outputs "hello" "world"
- saurik 9y agoOne nice thing about "new Promise()" calling the function immediately is that if you are prepared to provide the value immediately then you don't have to return into the runloop, but probably the reason I'd give for why delaying the call would be a horrible idea is that the vast majority of the time the promise is going to do some minimal amount of setup work and then... return to the runloop (and if it isn't, I am going to ask why you are using a promise). That means that the behavior they currently have of calling the function immediately minimizes returns to the runloop and provides performance as close as possible to what you would get if you hand-coded it using callbacks (the only overhead being the unlikely-to-be-optimized-away-fully-by-the-VM object allocations and indirect function calls; but like: this paradigm in a language with zero-cost abstractions would be perfect).
- xori 9y ago> if you are prepared to provide the value immediately then you don't have to return into the runloop It might just my own mental model. But if I'm using a promise, it is a future value. So I don't understand why you would ever want to do that. Plus that's what Promise.resolve() is for. I'd expect them to act more like the now defunct setImmediate() function. I concede that it may be more performant to do it this way as it results in less context switching, but I personally don't think performance should dictate a language's design of primitives.
- saurik 9y agoTo use Promise.resolve you have to know whether the value is ready or not before you enter the promise, but you should enter the promise and then check that status. There are very few situations where Promise.resolve should be used: it is essentially a weird performance optimization for constant values. A basic example is something like reading from a network buffer: you call read, and there might be data immediately or you might have to wait; and in JavaScript the way you read might involve a callback, so it isn't even like "check buffer and then use Promise.resolve as awkward special case" but instead "call read passing callback; if data is already there the callback is called immediately". This also comes up while implementing stuff like "a set of values that consumers can ask for a value from; if the set is empty they will have to wait until there is a value". Regardless, I legitimately believe the mental model of it not switching back and forth is fundamentally more correct for the primitive. The goal should also be that the abstraction has the same behavior and ordering semantics as doing it by hand. When you do it by hand, you essentially must run the code there immediately as otherwise there is no way to even run that code at all. Why would you ever want that code to be delayed? It frankly sounds like you are modeling Promise as if it meant Thread or something... a Promise is just a tiny adapter whose purpose is to change a wrap some setup code for accessing the value of a later event together into a common interface. A promise isn't doing the work: it is adapting the API of random models of doing future work (one-off callback APIs, random evented interfaces, etc.) to its own. Having this allows us to hack in (due to the lack of good monad support in most programming languages) async/await in a non-horrific way. If you want to do future work your first step should be to come up with a model for how your future work will happen, and then you use Promises just to do this adaptation, not to like, spawn some computation that will take time and which should happen later.
- codedokode 9y agoNo, you won't get the result immediately anyway because then() callbacks are called only on next event loop iteration. This protects from overflowing the stack, but might have small impact on performance.
- deleted 9y ago[deleted]
- saurik 9y agoOK. I see why they would have chosen to do that, and it disappoints me, but it seems to be weirdly more complex than that... this code prints the numbers in order (and continues to do so if you rearrange the calls to setImmediate and setTimeout or move them outside of the function either before or after)... so it is definitely returning from the function but it seems like the resolved value gets to jump the queue? (async () => { setImmediate(function() { console.log("4"); }); setTimeout(function() { console.log("3"); }, 0); console.log(await new Promise((resolve, reject) => { console.log("0"); resolve("2"); })); })().catch(); console.log("1");
- codedokode 9y agoI don't think it is a good idea to expect some specific order in executing callbacks here unless it is described in some specification.
- rmrfrmrf 9y agoThis isn't correct for native Promises. Native Promises flatten themselves out at the end of each tick and will do any synchronous work possible before either the Promise settles or there's something that needs to get thrown to the event queue. This all happens synchronously, although deferred, but still can block the app completely if someone is simply wrapping synchronous actions in Promises expecting them to be "async".