Skip to content

Commit 819f9ca

Browse files
authored
fix: do not return a rejected promise; throw it instead. (#123)
1 parent 0e7c5d2 commit 819f9ca

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

src/use-async-effect.spec.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,31 @@ it("does throw promise rejections", async (done) => {
213213
render(<TestComponent />);
214214
});
215215

216+
it("does throw promise rejections in loops", async (done) => {
217+
const TestComponent: React.FC = () => {
218+
useAsyncEffect(function* () {
219+
const value1 = yield Promise.resolve('foobar')
220+
expect(value1).toEqual('foobar');
221+
222+
for(let i=0; i<=3; i++) {
223+
try {
224+
yield Promise.reject(new Error("Something went wrong."));
225+
done.fail("Should throw");
226+
} catch (err) {
227+
expect(err.message).toEqual("Something went wrong.");
228+
}
229+
}
230+
231+
const value2 = yield Promise.resolve('hello')
232+
expect(value2).toEqual('hello');
233+
234+
done();
235+
}, []);
236+
return null;
237+
};
238+
render(<TestComponent />);
239+
});
240+
216241
it("logs error about uncaught promises to the console", async (done) => {
217242
const TestComponent: React.FC = () => {
218243
useAsyncEffect(function* () {

src/use-async-effect.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,30 +43,37 @@ export const useAsyncEffect = (
4343
const run = async () => {
4444
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4545
let result: IteratorResult<any> = { value: undefined, done: false };
46+
let lastError: Error | undefined = undefined;
47+
4648
do {
47-
result = generator.next(result.value);
48-
if (result.value && result.value.then) {
49-
try {
50-
result.value = await result.value;
51-
} catch (err) {
52-
if (isCanceled) {
53-
onCancelError(err);
54-
return;
55-
}
49+
try {
50+
result = !lastError
51+
? generator.next(result.value)
52+
: generator.throw(lastError);
53+
lastError = undefined;
54+
55+
if (result.value && result.value.then) {
5656
try {
57-
generator.throw(err);
57+
result.value = await result.value;
5858
} catch (err) {
59-
console.error(`[use-async-effect] Unhandled promise rejection.`);
60-
console.error(err);
61-
return;
59+
if (isCanceled) {
60+
onCancelError(err);
61+
return;
62+
}
63+
64+
lastError = err;
6265
}
6366
}
64-
}
65-
if (isCanceled) {
67+
if (isCanceled) {
68+
return;
69+
}
70+
onCancel = noop;
71+
onCancelError = noop;
72+
} catch (err) {
73+
console.error(`[use-async-effect] Unhandled promise rejection.`);
74+
console.error(err);
6675
return;
6776
}
68-
onCancel = noop;
69-
onCancelError = noop;
7077
} while (result.done === false);
7178
if (result.value) {
7279
cleanupHandler = result.value;

0 commit comments

Comments
 (0)