> Another way of solving this problem comes from the realisation that we only really need to keep track of the dependencies for a promise while the promise is in the pending state, because once a promise is fulfilled we can just execute the function right away!<p>This is a common gotcha in Javascript implementations, in that you think you want this, but you really don't! Now you never know if your code is synchronous or will run in a subsequent tick. Your call tree will look completely different depending on race conditions...<p>This comes up in user code as well; any time you write a function that takes a callback, it's probably a good idea to either always run it either in the same call tree or in a new stack, but never mix the two. It's usually easier to just do the latter using process.nextTick.
I have seen how Promises' concept was abused in a project at work. All the promises were just returning Future objects, and they were exposed everywhere. And, in case a future fails for some reason, there was no way to have a new Future: all users were doing future.get, resulting in an exception thrown to the caller.
What a mess.
Nicely done, thanks! Still, having to explain a concept as simple as eventual computation reinforces my belief that promises as a whole is broken, and should be done in something that looks like synchronous code with some help of the underlying runtime. (And no, ES7's async is not good enough for me here)
I found this document : <a href="https://github.com/kriskowal/q/tree/v1/design" rel="nofollow">https://github.com/kriskowal/q/tree/v1/design</a> very helpful to understand how promises work behind the scene
Also liked being able to access the author's reasoning and the motivations behind his design decisions
Another good classic about it is Domenic's you're missing the point of promises at <a href="https://gist.github.com/domenic/3889970" rel="nofollow">https://gist.github.com/domenic/3889970</a> from 2012
Nice summary! I wish I had this when I started getting into Promises a couple of months ago.<p>For a really interesting look ahead to how Promises (and more!) might address sync/async symmetry in ES6/7, check this out: <a href="https://youtu.be/DqMFX91ToLw" rel="nofollow">https://youtu.be/DqMFX91ToLw</a>
Really a lot more explanation than necessary. Get a feel by using them and using a debugger or just console.log to trace execution. Then compare with equivalent callback code and async/await with babel.<p>Then use async/await and look at node-modules.com to find modules that convert to promises so you can use async/await.
See section about handling error and promises. Very well done!<p>You won't see that in the typical "check out how cool promises are, async and fast all the things".<p>And promises indeed look cool, and make for nice short demos and they are easy to understand in short examples. Only when you start building a large applications based on them, where error handling has to be done, you start realizing they are bit like threads. Promise callback chains started from one event, can interfere with other promise callback chains that started from another event. And if they modify the same data, you now also have a race condition as well.<p>I would basically look at this statement "In the synchronous world, it’s very simple to understand computations when thinking about functions: you put things into a function, and the function gives you something in return" and follow through, but in a different direction -- pick the synchronous world if you can.<p>Sequential things should be sequential and concurrent things should be concurrent. Single request processing is sequential. For this request do x,y,z in order. Can't do y unless x finished. Well sit and wait for x to finish. But requests themselves can be concurrent and run in parallel. For example a request comes in, reads the database, updates the database, bumps metrics, makess other sub-requests and then responds. It is sequential and should be kept sequential. If you platform cannot handle that, think very well about your platform, and perhaps pick a better platform. What does that mean practically? It means picking green threads (Python gevent, eventlet), it means Elixir, Erlang, Go goroutines, Rust's threads. Streams can be used as a higher level abstraction sometimes and so on.