uncaught error from Promise.reject
See original GitHub issueA demo here.
Code related below, the race
code mostly comes from https://github.com/yelouafi/redux-saga/issues/183:
import { fork, call, put, race, take } from 'redux-saga/effects'
function * api () {
try {
let result = yield * callWithLoadingEffect(fetchApi)
console.log(result)
} catch (error) {
console.log('error', error)
}
}
// fetch data from reddit
function fetchApi () {
return fetch('https://www.reddit.com/new.json')
.then(
(response) => {
return Promise.reject('haha')
// return response.json()
}
)
.catch(
(error) => Promise.reject(error)
)
}
const delay = (ms) => new Promise((resolve) => setTimeout(() => resolve(true), ms))
export function * callWithLoadingEffect (fn) {
try {
const task = yield fork(fn)
const taskPromise = new Promise((resolve, reject) => {
task.done.then(resolve, reject)
})
let {timeout, result} = yield race({
timeout: call(delay, 100),
result: taskPromise
})
if (timeout) {
yield put({
type: 'SHOW_LOADING'
})
result = yield taskPromise
}
yield put({
type: 'HIDE_LOADING'
})
return result
} catch (err) {
yield put({
type: 'HIDE_LOADING'
})
throw err
}
}
export function * helloSaga () {
console.log('Hello Sagas!')
while (true) {
yield take('FETCH')
yield fork(api)
}
}
If I returned Promise.reject('haha')
when response comes back, proc.js
would print errors:
I thought the try {} catch () {}
in callWithLoadingEffect
would catch the error as doc said, and from the console, I can see api
generator did catch the error, but that uncaught haha
seems like that it isn’t true, any suggest?
Thanks.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:1
- Comments:16 (16 by maintainers)
Top Results From Across the Web
Promise reject() causes "Uncaught (in promise)" warning
This happens because you do not attach a catch handler to the promise returned by the first then method, which therefore is without...
Read more >Promise.reject() - JavaScript - MDN Web Docs
The Promise.reject() method returns a Promise object that is rejected with a given reason.
Read more >Error handling with promises - The Modern JavaScript Tutorial
Promise chains are great at error handling. When a promise rejects, the control jumps to the closest rejection handler.
Read more >Promises - Error Handling - Beginner JavaScript - Wes Bos
What does that log "Uncaught (in promise)" mean? It means that there was an error in one of our promises, but we did...
Read more >Tracking Unhandled Promise Rejections - TrackJS
When a promise is rejected, it looks for a rejection handler. If it finds one, like in the example above, it calls the...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I think you can get the same effect and a simpler code with try/finally
IMO, you shouldn’t use any try/catch with a join effect. The main purpose of a join is to wait for a task to terminate. The task should handle all its errors and let only bubble unexpected ones (see below)
I’d rather separate errors in 2 classes
At least the best way to work with the redux-saga fork model is to handle business errors from inside the forked tasks themselves an let bubble only bugs which can be caught at some higher level.
In fact I can even go farther and recommend to not use try/catch for business error handling because javascript IMO lacks the necessary constructs for typed catch blocks. consider this code
because the catch block catches all errors: both business Errors (server error, timeout …) and bugs (Api.gett is not function). The code reacts the same on both types; I don’t think this the desired behavior. Typically we want to put an Error action only on server errors and let bubble any bug. In typed languages like Java you can achieve this with typed catch blocks like
catch (ServerError err)
But JS lacks this feature.The best way to think of the fork model is as dynamic parallel effect. A saga has a main flow (its own body => the main task) and can fork parallel flows dynamically. Like in parallel effects, cancelling the saga will cancel all the parallel tasks (main task + forked tasks). The saga will terminate after all parallel tasks terminate, and an error from one of the tasks will abort the whole parallel effects.
It may sound restrictive but this has the advantage of having a much simpler model to reason about. You know precisely how do Return values, Errors and Cancellations propagate, … The other option is the very flexible Promise model but also its well known issues (esp. Error propagation => unhandled rejections, error swallowed, not to mention the difficulty to define a simple and consistent model for Cancellations)
Thanks, I think it makes sense to separate those errors in my code.