Problem with calling actionAsync inside another actionAsync without waiting
See original GitHub issueI bumped into an issue with actionAsync
. I have poked into mobx-utils
to have a test to reproduce my problem. Here it is
test("calling promise without task", async () => {
mobx.configure({ enforceActions: "observed" })
const values = []
const x = mobx.observable({ a: 1 })
mobx.reaction(() => x.a, v => values.push(v), { fireImmediately: true })
const f1 = actionAsync("f1", async () => {
// await task(Promise.all([])); // LINE 1
// await task(Promise.resolve([])); // LINE 2
// await task(Promise.all([])); // LINE 3
});
const f2 = actionAsync('f2', async () => {
f1(); // LINE 0
x.a = 2;
x.a = await task(Promise.resolve(3));
});
await f2();
// expectNoActionsRunning() // this line will fail if I uncomment LINE 1 and LINE 2
expect(values).toEqual([1, 2, 3])
})
Notice my LINE 0
, here, I’m calling an actionAsync
without await
inside of another actionAsync
. This test, as it is right now, passes, but when I start to uncomment LINE 1-3
, strange things happen.
Uncommenting LINE 1
, I’ll get:
Error: [mobx-utils] invalid 'actionAsync' context when finishing action 'f1'. an action context
for 'f2' was found instead. did you await inside an 'actionAsync' without using 'task(promise)'? did you forget to await the task?
Uncommenting LINE 1
and LINE 2
, I’ll get a failed test:
expect(received).toEqual(expected) // deep equality
- Expected
+ Received
Array [
1,
2,
- 3,
]
so it means the f2
is finished before await task(Promise.resolve(3))
And lastly, uncommenting LINE 1
, LINE 2
, and LINE 3
will make the test pass, then really any other line I add after LINE 3
doesn’t matter.
@xaviergonz Hope I can have your input about this. It’s really confusing to me. I think my use case is justified because there would be time when you don’t want to wait for a promise inside of an actionAsync
, unless you could give me a suggestion on how to do that gracefully (I can do this with flow
). Thank you so much!
EDIT: as for why on earth would I do Promise.all([])
that’s because I was doing a parallel processing like this
Promise.all(this.cars.map(car => new Promise(resolve => setTimeout(() => {
/* do something here with car */; resolve() }, 0)));
but my this.cars
was empty and I saw errors thrown by mobx-utils
.
Issue Analytics
- State:
- Created 4 years ago
- Comments:10 (5 by maintainers)
@blacksteed232 Just created a PR that fixes this
That’s because the requirements for actionAsync to work are:
In this case what I suggest you to do is to either:
That way there are no dangling promises and it is neatly controlled by the parent action.