5 ms·
I have also found Promises very hard to reason about at times: "okay, so I have some code here, and when exactly is this run?" can be a difficult question to an
by arp242 3y ago
I have also found Promises very hard to reason about at times: "okay, so I have some code here, and when exactly is this run?" can be a difficult question to answer with Promises. Part of that is inherent in async code, but part of that is also because IMHO Promises make it harder than it needs to be.
I never really used Java, but I have used Ruby and Python (IIRC Python's APIs were modelled on the Java ones) and I agree it can be painful. The thing is, even with an awkward async implementation it's something you have to deal with relatively infrequently when synchronous is the default (as it is in most languages). When you do it can be a pain, but I'd rather have this "occasional pain" vs. "pain every time I want to do any I/O operation".
Personally I like how Go does things.
- peferron 3y ago> I have some code here, and when exactly is this run? If there are `await` keywords previously in the function, then the line you're looking at will run after these async calls are done. Otherwise it'll run ASAP. Is there something else to it?
- consilient 3y agoPeople often get confused because they expect `await` to sequence promise resolution too. For example const example = async () => { const ifError = Promise.reject("something went wrong") const value = await someOtherPromise() await (valueIsOk(value) ? runNextStep(value) : ifError) } will always throw.
- bilalq 3y agoI don't think I follow. Your example left out all the definitions of these functions, so you can't really deterministically say what will happen. If `someOtherPromise()` fulfills, `valueIsOk(value)` evaluates to `true` or truthy, and `runNextStep(value)` fulfills, `example` will fulfill and not reject. If any of those conditions don't hold, `example` settles as rejected.
- consilient 3y agoThe issue is that `ifError` throws whether `example` fulfills or not. Promised values are sequenced by `async`, but promise side-effects are sequenced like side effects of any other javascript statement.
- bilalq 3y agoSure, ifError rejects, but I don't think the behavior here is surprising or strange at all. This is exactly how one would want it to work. If you wanted to await it, you could do that. Is the concern you're raising that people may accidentally orphan floating promises? That can be addressed with linter rules. [1][2] [1]: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md https://github.com/typescript-eslint/typescript-eslint/blob/... [2]: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-misused-promises.md https://github.com/typescript-eslint/typescript-eslint/blob/...
- consilient 3y ago> but I don't think the behavior here is surprising or strange at all. Tell that to my junior coworkers. It's probably the single most common cause of async bugs in our codebase.
- bilalq 3y agoAre you running those two lint rules I mentioned? They should completely remove cases of accidental floating promises.
- consilient 3y agoYes, but the floating isn't the issue: throwing in my example was just a concrete stand in for promise side effects in general. Running queries you only need in one not so common branch before the conditional gets checked, for instance.
- ttfkam 3y agoMy code is running <- no await My code is accessing another resource (storage, network, etc.) <- await It's really not that complicated. If you're surprised by the presence of absence of a Promise, you might want to take a moment to understand what is being processed. There's a good chance there's a gap there that extends beyond a simple keyword in JS.