Live data from Hacker News

How do Promises Work?

robotlolita.me

71–80 of 91 posts

Re: How do Promises Work?

#71
post #30
post #14

Earlier quoted context omitted.

In a typical web API in node that I've seen, by function count I'd say around 60-70% of code is asynchronous.

Well yeah, I usually end up writing lots of async code because you pretty much have to since all the libraries assume that's what you want, but shoehorning in dependencies (promises, callbacks, callbacks mutated into promises by a promises library—it's a mess) until it could have just as well been written as at most two threads. So it's async in pattern but not in fact.

Most of the time that IS what you want in general in node, as if you start running anything with even moderate CPU time (let alone a call to an external service) you block the event loop and chug the system. The big performance gain you get with node in the form of max simultaneous connections per clock you get from not blocking. Most (95%+) of packages I've seen use callbacks, and maybe ~10% expose promise interfaces even if they use them internally.

Re: How do Promises Work?

#72
post #45

Earlier quoted context omitted.

> Either you use the leaky blocking IO abstraction over the async IO What do you mean the leaky blocking IO. It is the non-blocking IO that is leaky, isn't it. If at the business logic there is a request being processed that needs to go through steps a,b,c and then return. b, can't be done unless a finishes and c unless b finishes is mapped pretty cleanly to an execution context of a thread/actor/goroutine/task/proce…

What I meant is that blocking IO is a leaking abstraction, because IO is always asynchronous. What blocking does is adding an extra step (start the process AND waiting for the result) and thereby hiding something. I agree that if you have some pure linear steps (do A, then do B, then do C, and probably use the result from the last step for the next), then the synchronous abstractions work fine. But as soon as you add…

[deleted]

Re: How do Promises Work?

#73
post #45

Earlier quoted context omitted.

> Either you use the leaky blocking IO abstraction over the async IO What do you mean the leaky blocking IO. It is the non-blocking IO that is leaky, isn't it. If at the business logic there is a request being processed that needs to go through steps a,b,c and then return. b, can't be done unless a finishes and c unless b finishes is mapped pretty cleanly to an execution context of a thread/actor/goroutine/task/proce…

What I meant is that blocking IO is a leaking abstraction, because IO is always asynchronous. What blocking does is adding an extra step (start the process AND waiting for the result) and thereby hiding something. I agree that if you have some pure linear steps (do A, then do B, then do C, and probably use the result from the last step for the next), then the synchronous abstractions work fine. But as soon as you add…

> because IO is always asynchronous.

Creating a socket() creates a blocking socket by default, doesn't it. Doing a recv on it, blocks the current thread. Pretty sure by default IO is synchronous. Sure at some point they are all connected to a single wire plugged into the switch and there is a single network card. But if you are thinking that low, then well javascript is not the framework to talk about we are in firmware, dpdk, and driver land.

The socket API is synchronous. Do do stuff "asynchronously" you have to go the extra mile and enable turn on some options, use select/poll/epoll callbacks, explicitly pass state around between callbacks etc.

> What blocking does is adding an extra step (start the process AND waiting for the result) and thereby hiding something.

See to me at the socket layer non-blocking is the extra step. Having to enable a new mode, then use some extra polling hub to see which socket has data etc. That mixes context between separate requests, etc.

> I often end up implementing quite complex state machines for heavy IO related code

In specializes cases for performance reasons I think switching to asynchronous, but that is a rather special case. It works for short callback chains and situations optimized for IO throughput say things like nginx or haproxy. Doing it for an online store or some business middle layer would be very tricky.

Re: How do Promises Work?

#74
post #48
post #44

See section about handling error and promises. Very well done! You won't see that in the typical "check out how cool promises are, async and fast all the things". 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 threa…

Rust no longer has green threads. Another good way to make things sequential is C#-style async/await, which is enough syntactic sugar over promises that everything looks sequential again.

It has regular threads but with appropriate data race safety guarantees. So that won't help in context when large number of concurrent contexts are happening, but perhaps it should first become a bottleneck and then solved, because it might just be good enough.

Re: How do Promises Work?

#75
post #43

Earlier quoted context omitted.

This is a common gotcha in Javascript implementations, in that you think you want this, but you really don't! No, I really, really, DO want this. And I want my entire codebase written in such a way that this is fine. You need consistent abstractions to make asynchronous logic flow comprehensible. And once you have them, stick to them rigorously. Promises are such an abstraction. Build on it, don't ruin it. Yes, there…

I think you (or I) misunderstand what you're replying to. When they said "you really don't want this", they're saying you don't want promises to sometimes be async and sometimes resolve in the same tick. Always make them async. That agrees with you, since it would mean you can always treat promises the same.

The general pattern is write code to do initial processing, set up promises, return a promise depending on those promises that will do something.

The promises you set up should always be assumed to do things in whatever order they happen to happen. Your code that does interesting stuff happens before any promises are seen. The interesting code in your returned promise will happen after the necessary promises are resolved.

As long as things are always set up this way, you'll be fine no matter how the promise library is set up. Which is good because unexpected implicit dependencies are a problem.

Re: How do Promises Work?

#76
post #24

> 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! 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 o…

Promises also solve this problem. If you immediately resolve a promise it isn't actually resolved until the next event loop "tick": new Promise(resolve => resolve("resolved!")).then(result => console.log(result)); console.log("next statement"); Prints "next statement" then "resolved!".

It's actually not the next event loop tick (or it's not supposed to be; some implementations get this wrong). Promises use microtasks, so an already-resolved promise dispatches at the end of the current tick.

Re: How do Promises Work?

#78
post #8

Earlier quoted context omitted.

NodeJS: you needed 5% of your code to be async, so we made everything async so you get to write awkward async-but-not-really code for the other 95%, too. That's better, right? At least that's how it's always felt when I've used it for anything non-trivial yet well within its typical set of use cases.

Despite the downvotes, you are absolutely correct. My feeling, after working on a moderately complex server application in Node is that it was designed for only very simple applications that can be done with one level of callback. I find the "it works this way because its better" cult quite irritating. It works that way because the #*(^#$&^ JS interpreter isn't multithreaded.

It wouldn't even need to be multithreaded, I don't thnik. You could have some green threads-type system, using asynchronous I/O, a single-threaded server, and something along the lines of Lua's yieldk. Have a new script spring into life for each connection, suspend it when an I/O operation starts, and resume it when the results are ready (or when something goes wrong). I think this will be what Erlang does.

(I'm sure there are potential problems with this, but hopefully it would be overall no worse than the current situation, while being easier to work with.)

Re: How do Promises Work?

#80
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.

Then use async/await and look at node-modules.com to find modules that convert to promises so you can use async/await.

Post reply on HN