question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Errors thrown in an Async#map don't always become Rejected

See original GitHub issue

Describe the bug If an error is thrown in an Async#map, it doesn’t always become a Rejected.

To Reproduce

const { Async } = require('crocks')

Async((rej, res) => res('a'))
  .map(() => { throw new Error('bad') })
  .fork(err => console.error({ err }), val => console.log({ val }))

Expected behavior I would expect an object shaped like { err } to be logged to console.error, but instead the error is thrown and logged by itself, and neither of the forked functions are called.

Additional context If you wrap a Promise instead, it works as expected:

Async.fromPromise(() => Promise.resolve('a'))('b')
  .map(() => { throw new Error('bad') })
  .fork(err => console.error({ err }), val => console.log({ val }))

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:12 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
flintinatuxcommented, Apr 18, 2019

My apologies. I took the bait and wandered into opinion territory, and now we’re off topic. I’ll wander back.

The issue at hand is this:

  • If I convert a Promise into an Async via Async.fromPromise, then errors thrown in a .map() are caught and converted to a Rejected.
  • If I create an Async with the regular factory function, errors thrown in a .map() are not caught.

I find this mismatch in behaviour to be unexpected. Am I incorrect in feeling this way? If this should be expected behaviour, I guess at the very least I would want it documented to try and avoid surprises.

1reaction
evilsoftcommented, Apr 19, 2019

@flintinatux I think you hit the nail on the head with the fromPromise function. I think this may be where the issue lies. So no matter what, this behavior will need to stay in place or it will invalidate Async as a Functor and all Natural transformations from other Sum Types also become invalid. Not to mention any Functor Compositions (Nested Functors is a way to view these)

So the reason it has to work this way is because in the Category of (gotta squint a little and ignore some bottoms) Javascript Types and Functions, Promises were created with this Error Handling in place. In order to provide a valid Functor, it MUST behave the same way in its source category when we get Async involved.

The issue is that we do not know the behavior when dealing with a Promise at the head or “chain”-ed in. Sometime it will throw, sometime it will not, depending on if fromPromise created the Async or not.

So the user of a crocks Async could alway treat it as it could blow and chain(tryCatch(fn)) one could never use map again without making sure it was also caught somehow, but I see how that may not be intuitive for the beginning/casual user.

Another option would be to somehow (don’t know how yet, maybe with how the type is logged) signal to the user that a promise is in the mix.

But no matter where we go, I agree to start we need good documentation around the what and why of this behavior.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Throw Errors From Async Functions in JavaScript?
Async functions and async methods always return a Promise, either resolved or rejected. You must attach then() and catch() , no matter what....
Read more >
How to avoid uncaught async errors in Javascript
In this article, you'll learn about a few cases where async exceptions bubble up and become uncaught errors. You'll learn why they happen ......
Read more >
Handling Errors (Rejections) in async/await inside Array#map
So in function b I try to get some async data (from a database). It fails and throws an Uncaught Promise Rejection. How...
Read more >
async - Documentation - GitHub Pages
async.map ... The same as reject but runs a maximum of limit async operations at a time. ... Results are always returned; however,...
Read more >
Writing Promise-Using Specifications - W3C
... always return promises; 4.1.2 Rejection reasons must be Error ... not found: for example asyncMap.get("key") should return a promise for ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found