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

asyncResult action call gives an "Uncaught (in promise)" error #296

Closed
pierrepinard-2 opened this issue Mar 18, 2015 · 21 comments
Closed

asyncResult action call gives an "Uncaught (in promise)" error #296

pierrepinard-2 opened this issue Mar 18, 2015 · 21 comments

Comments

@pierrepinard-2
Copy link

When I call an asyncResult action and when the triggered async process sends back an error (for example: "401 unauthorized"), everything works fine but I get another error in the console: "Uncaught (in promise) ... PublisherMethods.js:168":

var Reflux = require('reflux');

var someActions = Reflux.createActions({
    doThis: {
        asyncResult: true
    },
    // ...
});

someActions.doThis.listen(function (arg) {
    someAsyncProcess(arg)
        .then(this.completed)
        .catch(this.failed);
});

// elsewhere in the app:
someActions.doThis(arg);

// -> if someAsyncProcess sends back an error, another error in the console:
//     "Uncaught (in promise) ... PublisherMethods.js:168"

Am I doing it wrong, or is there a bug in the asyncResult actions ?

@afrojas
Copy link

afrojas commented Mar 18, 2015

I'm having this issue as well. Below are my various experiments

let ProjectActions = Reflux.createActions({
  'update':  {
    asyncResult: true
  }
});

ProjectActions.update.listen((projectModel, organizationSlug) => {
  if (false) {
    ProjectActions.update.completed();
  } else {
    ProjectActions.update.failed();
  }
});
// "Uncaught (in promise)..."

As expected, but just for completeness, swapping asyncResult: true for children: ['completed', 'failed'] is the same error.

However this does work just fine:

let ProjectActions = Reflux.createActions({
  'update':  {
    children: ['completed', 'failure']
  }
});

ProjectActions.update.listen((projectModel, organizationSlug) => {
  if (false) {
    ProjectActions.update.completed();
  } else {
    ProjectActions.update.failure();
  }
});

I also get the sense I'm doing something wonky...

@kembuco
Copy link

kembuco commented Mar 24, 2015

I was running into this as well and it was driving me batty. I'm pretty sure I know what the issue is, but I'm not sure what the correct solution is. However, there is a workaround you can put in your code to at least prevent the error from popping up in the console.

var Reflux = require('reflux');

var someActions = Reflux.createActions({
    doThis: {
        asyncResult: true
    },
    // ...
});

someActions.doThis.listen(function (arg) {
    someAsyncProcess(arg)
        .then(this.completed)
        .catch(this.failed);
});

// elsewhere in the app:
someActions.doThis(arg).catch(function() { /* prevents "Uncaught (in promise) error */});

The key bit being that catch there at the end.

The problem is that when the "doThis" action is called a promise is setup that listens for "doThis.failed" to be called. Of course, when your "someAsyncProcess" promise gets rejected, the "doThis.failed" gets called as expected. However, that also triggers a reject on the promise that Reflux sets up in the generated function for the action. Because there isn't a catch setup for that, the promise API throws an error.

I'm still not quite sure I understand why reject is called when the failed child action is triggered as it seems like it should work the other way around. I'm sure there is a good reason for it.

@jankuca
Copy link

jankuca commented Mar 24, 2015

Are you using the latest code? I believe this might have been fixed by #267.

@kembuco
Copy link

kembuco commented Mar 24, 2015

Yes. I just checked and I have the latest code. From the diff, it looks like PublisherMethods#promise is providing a catch for the promise that is supplied by the caller's async function. However, the issue arises when reject is called on the promise created in the PublisherMethods#triggerPromise function.

@pierrepinard-2
Copy link
Author

Thank you @afrojas and @kembuco for your deeper analysis. It looks like the call of an asyncResult action triggers the action as a Promise. I guess it's a (non blocking) bug.

@nuschk
Copy link

nuschk commented Mar 24, 2015

👍
Having the same problem as well. Thanks for fixing!

@jessepollak
Copy link

I'm having this same issue, would like to see a fix. Let me know if there's anything I can do to help :)

@spoike spoike added the bug label Apr 7, 2015
@spoike spoike added this to the 0.2.8 milestone Apr 7, 2015
@danishleo
Copy link

👍 also experiencing this bug

@VladimirPal
Copy link
Contributor

Same bug:(

@chriserik
Copy link

👍 Same here. Thanks for fixing!

@eblanshey
Copy link

Having this issue as well. This error doesn't happen in all failed async cases, which is strange. @afrojas's solution worked -- simply rename the "failed" method to "failure" or something else.

@almoraleslopez
Copy link

Same problem here. Thanks to @afrojas solution. Working fine.

@spoike spoike modified the milestones: Roadmap, 0.2.8 Jun 10, 2015
@simenbrekken
Copy link

I needed completed and failed actions to include the arguments they were orginally called with so I ended up working around this using the sync property:

const Reflux = require('reflux')

function createAction(promiseFactory) {
  const action = Reflux.createAction({ sync: true, children: ['completed', 'failed'] })

  if (promiseFactory) {
    action.listen((...args) => {
      promiseFactory(...args)
        .then(res => action.completed(res, ...args))
        .catch(res => action.failed(res, ...args))
    })
  }

  return action
}

@airwin
Copy link

airwin commented Jun 29, 2015

+1 @simenbrekken

@LongLiveCHIEF
Copy link

Closing in light of #352

@pierrepinard-2
Copy link
Author

Thank you @LongLiveCHIEF for your insight on the topic.
However, I am not sure I understood the reason why you closed this issue: do you mean that in a near future, the call of an "asyncResult" action will no longer trigger the action as a Promise (side-effect, or shortcut...)?

@LongLiveCHIEF
Copy link

I don't know for certain what the future holds yet, but what I'm working on at the moment is a model that means actions are subscribable and asynchronous by default, which changes the paradigm of "triggering" the response.

the reason I closed the issue, is because there is a bug with how the current implementation works, and it doesn't work as intended. It's a big of a design bug, more than a code bug though, so it's not something that can be fixed with same api implementation. (via side-effect/shortcut).

Because of how promises are intended to work, it's actually easier just to use promise methods to trigger handling, instead of relying on shortcut methods.

@pierrepinard-2
Copy link
Author

Allright, thank you for the details.
I used a way to work around this "design bug" anyway; my code's working fine for the moment.
Good luck for your work on the new model!
Best regards,

@mvandiest
Copy link

So, renaming to something other than 'failed' fixes the issue. But I'm having trouble seeing why the name itself causes the issue. Can someone shed some light on this?

I've looked through reflux-core and refluxjs and can't see why the name is important.

Thanks

@benglass
Copy link

We are also running into this issue as a result of using listenAndPromise to wire an asyncResult action with completed/failed children to a method that returns a promise.

This is already mentioned here but approaches the seem to work I am listing below

  1. Add sync: true to the action definition and use listenAndPromise
myAction: { sync: true, asyncResult: true }

myAction.listenAndPromise(myPromiseReturningMethod);
  1. Do not use asyncResult, specify children manually (do NOT use 'failure' child name) and wire up using listen
myAction: { children: ['completed', 'failure'] }

myAction.listen(() => {
    myPromiseReturningMethod.then(myAction.completed).catch(myAction.failure);
});

As noted elsewhere there seems to be a race condition when NOT using sync: true with the failed child method of an async result. Unless I'm missing something this means that listenAndPromise by default is broken and will subject you to errors in the console unless you add sync: true. I tried and failed to read the PublisherMethods code that seems responsible for this race condition that happens when combining sync: false with asyncResult: true

I was unable to clearly understand why the "failed" child action name is significant and causes different behavior for listenAndPromise

I am currently using 0.2.8 of reflux.

@gippy143
Copy link

gippy143 commented Jan 11, 2017

Hi All,

I was struggling with the same issue but I got it fixed by making minor change. Add async : false in all AJAX get requests. Consider the code below:

type : "GET",
url : "/someUrl/",
dataType : 'json',
async : false,

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