Promises are not neutral enough
staltz.com
Promises are not neutral enough
1–10 of 133 posts
Re: Promises are not neutral enough
#2Re: Promises are not neutral enough
#3Re: Promises are not neutral enough
#4I 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"Re: Promises are not neutral enough
#5I started working with JS promises specifically when they were barely available in a beta runtime. It took me over a year of working with them to really get a feel for them, now it's been far longer. That's because while you can "understand" the description and use it just fine, but a deeper comprehension and intuition takes much more time. I experimented a lot and insisted on writing my own helpers from scratch, without looking up other people's code, because I wanted to get a feeling for the details.
This article seems quite artificial to me, the problems mostly made-up.
I don't see the point of the first complaint. If you don't want to start right away chain it to something that it should wait for. If it should not wait, then it can start right away. Her writes "Functions rescue us in this case because functions are lazy." which I don't quite understand: what is he running through promises if not functions? Hi "betterFetch" example mixes synchronous and promise syntax - how about using async/await if you prefer the former? I admit though I don't quite get the point of that example.
I don't understand the whole "run a promise" idea either - because you don't "run a promise", that whole notion has nothing to do with what "promise" means. Just look at the word! It represents a (wrapped) future value. Where does the idea of "running it" come from? How do you "run" a (future) value?
You have a function and it is quite easy IMO: Using a promise you chain it to whatever you want to wait for. These days you can even use semi-synchronous syntax (async/await). "Running a promise" makes no sense to me, you run functions, and I don't see where the difficulty lies here?
The second point, cancellation, has been discussed very, very thoroughly - after all, this was on the table to be standardized. One of the issues he raises is the same as point one - if you have a chain it's automatic. The main issue of cancellation is that you have zero control over the actual asynchronous operation that the promise actually stands for - because this is controlled by the OS alone! If you started I/O, what does "cancelling the promise" mean?
1. If it is still waiting: If you don't want to run something make sure the previous step returns a rejected promise. You can easily "cancel the promise". Just let your promise function check something in the parent scope (via callback or it is in its lexical scope) when its chained function starts, and if that says "you are canceled" then don't do it. You can put such a check as a standalone function anywhere in the promise chain you created, just let that "amIcancelled()" function throw or return a rejected promise. The whole chain aspect is something that the article is missing.
2. If the code is already running: you cannot cancel the actual (OS controlled) asynchronous operation, nor can you cancel a running JS function (unless you use async/await see bottom paragraph).
I agree that promises are not perfect, but async/await - not mentioned at all! - makes it a bit easier for many people - as long as they don't forget one thing: Even if your functions now look like synchronous ones there is a fundamental difference: A synchronous JS function is never interrupted by any other code. An async function is suspended and other JS code gets to run in the middle of it when it encounters an "await". This is something new first introduced by generators, before that JS functions were atomic (now some are not).
Re: Promises are not neutral enough
#6The alternatives look nice. There's just one requirement missing: streaming progress information to the listeners.
You then have something like an async generator, which is like a fusion of asynchrony and sequence?
Except generators are pull not push, so instead you have a promise that accepts a function that operates on a sequence?
I don't know if this pattern is common somewhere, someone who does please explain!
Re: Promises are not neutral enough
#7This 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 organ…
Re: Promises are not neutral enough
#8So this looks like a trade-off: you could make function composition easier only by making Promises less suitable for their original purpose. By going generic, you lose an important guarantee that a Promise is just a value.
Re: Promises are not neutral enough
#9Re: Promises are not neutral enough
#101. Eager, not lazy - I think it was a mistake for the promise constructor to take a function, and in that way lead the users to believe the promise represents a computation. Creating a pair of promise and future (the latter as the producer side, like in C++) would be much cleaner. I disagree that lazy would be more general, you can simulate lazyness with functions, but you couldn't eliminate the performance cost of creating the unnecessary closure with a lazy solution. Regarding getUserAge - the common case for that function would be to take the user ID as the parameter (and hence would be lazy by construction), the parameterless version is a special case.
2. No cancellation - cancellation is much better represented with cancellation tokens (even C# Tasks cancel with cancellation tokens, so does fun-task mentioned at the end, though in non-composable way) - you cannot build a generic solution that can cancel the right computations. With cancellation tokens it's clear what cancels what.
3. and 4. (as well as being allowed pass non-promises to places where only promises make sense, like Promise.all and await) are unfortunate accidents that make typed environments (e.g. TypeScript) harder to work with but are not that important as 1 and 2.