Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[v3] Async Transition: forward resolved value #106

Open
Andreyco opened this issue Jan 25, 2017 · 6 comments
Open

[v3] Async Transition: forward resolved value #106

Andreyco opened this issue Jan 25, 2017 · 6 comments

Comments

@Andreyco
Copy link

Andreyco commented Jan 25, 2017

Would it be possible to forward resolved/rejected value from async transitions?

@jakesgordon
Copy link
Owner

Good question, I'll have to think about it.

I'm not sure what the mechanism would be for forwarding the resolved/rejected value back to the user. Perhaps just storing it ephemerally as an attribute on the fsm itself?

Also this could be complicated by the fact that, in theory, there could be multiple async steps in a single transition (you could be async during onLeaveState and during onEnterState in the same transition) so there could be multiple resolved/rejected values for a single transition.

Do you have an example of how you might want your calling code to look with this feature?

@Andreyco
Copy link
Author

Andreyco commented Feb 4, 2017

Hello!

First, here is example of calling code...

- current state: paymentMethod
- next state: review

// Registered hook
onLeavePaymentMethod: function(lifecycle, payload) {
    return new Promise(asyn function(resolve, reject) {
        // do async call to extenal service provider. Based on response, either resolve, or reject.
        try {
            const paymentMethodToken =  validatePaymentMethod(payload);
            resolve(paymentMethodToken);
        } catch (e) {
            reject(e);
        }
    })
}

// Attempt state transition
const response = await fms.review();

// Decide what to do based on response.

Event better, rejected transition would throw. Calling code could be changed to following...

try {
    const paymentMethodToken = await fsm.review();
    // e.g: store valid payment token for future use
} catch (e) {
    // e.g: bail out, display validation error
}

Unfortunately, I am not sure about multiple async steps, while transition from state A -> B. Do you have use case in mind?

@Andreyco
Copy link
Author

Andreyco commented Feb 4, 2017

Actually, rejecting with value does forward rejection value.

onLeavePaymentMethod: function(lifecycle) {
    return new Promise(async function(resolve, reject) {
        reject('test value');
    }
}

const response = await fsm.review();
console.log(response); // 'test value'

On the other hand, resolve does not...

onLeavePaymentMethod: function(lifecycle) {
    return new Promise(async function(resolve, reject) {
        resolve('test value');
    }
}

const response = await fsm.review();
console.log(response); // true

@tkalfigo
Copy link

@Andreyco I registered a couple of days ago a related issue before seeing yours. I'm also on branch v3.

My issue was regarding the case where one of the lifecycle methods is rejected. The transition is stopped from happening and any subsequent lifecycle methods are not called. This is as expected. But the inital transition caller proceeds with normal resolution even though, as you point out, the passed value is the lifecycle method's rejection value, which I feel is counter-intuitive. I'd have expected the transition caller's promise to be rejected as well.

@jakesgordon You are right that it gets complicated in the case when all lifecycle methods resolve. Which of the resolved values should you forward to the transition caller? But in the case where any one of them is rejected,, there is only one value to be forwarded to the transition caller. Correct?

@jakesgordon
Copy link
Owner

Both of these issues should be fixed in v3 branch (shortly to be released to npm as v3.0.1).

Any async lifecycle event that is rejected will now throw an exception so the transition callers promise will also be rejected.

Any async lifecycle event that is resolved will pass the result thru to the end of the lifecycle chain - NOTE: if you have multiple async lifecycle events in a single transition then its last-one-wins.

@kr1sp1n
Copy link

kr1sp1n commented Nov 14, 2017

@jakesgordon When I tested async resolving every async result from event handlers before doTransit are not passed thru. The doTransitfunction signature does not pass the result. The regarding tests (lifecycle events can be deferred using a promise) are not right because you do not test a single result from every method. Instead you just test the result of the last method onAfterStep. So what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants