2

I have a vuex action like this

myAction() {
    const deferred = $.Deferred();
    setTimeout(() => deferred.resolve(), 3000);
    return deferred.promise();
}

in my vue component

myMethod() {
    this.myAction().fail(() => ...do something...);
}

throwing error:

Uncaught TypeError: this.myAction(...).fail is not a function

The code was working fine, but issue appeared once I updated my npm modules/vue-cli/webpack etc. Another point is if I change .fail to .catch then it works fine. But the question is why .fail is not working?

3
  • What you describe would happen if myAction failed to explicitly return the jQuery promise (it would return an implicit wrapper promise instead). Did you test the simplified example above and still get the error? Just wondering if your actual action is different enough from the example.
    – Dan
    Commented Nov 13, 2020 at 10:05
  • thats exactly what I have tried, this.myAction().catch(...) is working but this.myAction().fail is not
    – coure2011
    Commented Nov 13, 2020 at 11:50
  • I m using vuex 3.4.0
    – coure2011
    Commented Nov 14, 2020 at 13:08

1 Answer 1

1

Beginning with Vuex 3.4.0, actions always return a native promise. In past versions, Vuex only checked whether an action returned a thennable object, i.e. anything with .then property. If not, it wrapped the action return value in a new promise. But if so, it simply returned the object without wrapping it, assuming it was a promise. Starting with 3.4.0, Vuex wraps even thennable objects.

So in the past, the $.Deferred promise was able to slip by, because it has a .then method which returns a $ promise object with a .fail method. But now it gets wrapped in a native promise.


registerAction

If you inspect the Vuex source, you see that registerAction didn't change from 3.3.0 to 3.4.0. This is where non-thennable return values are wrapped in promises. It hasn't changed:

function registerAction (store, type, handler, local) {
  ...
  if (!isPromise(res)) {
    res = Promise.resolve(res);
  }
  ...
}

store.dispatch.prototype

But store.dispatch.prototype did change. It used to just return the .then method:

return result.then(function (res) {
  ...
})

But now it always returns a promise wrapper:

return new Promise(function (resolve, reject) {
  result.then(function (res) {  // Doesn't return the inner promise either
    ...
  })
})

And the wrapper doesn't bother to return the inner result either. It seems Vuex has decided to normalize the return value of actions so that it's guaranteed to be a native promise.

1
  • 1
    Here's a fiddle I used when testing some stuff
    – Dan
    Commented Nov 14, 2020 at 16:41

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.