Vue: Create an ".async" modifier for event handlers

Created on 3 Aug 2019  Â·  6Comments  Â·  Source: vuejs/vue

What problem does this feature solve?

In an event handler, one can easily mix property modifications and method calls (which is great), as in:

<span @click=" accumulator += fetchNextItem() ">do it</span>

However, if the called method is async, one need to actually wrap this code in an additional method like:

<span @click=" fetchAndAccumulateNextItem() ">do it </span>
....
methods: {
    async fetchAndAccumulateNextItem() {
        this.accumulator += await this.fetchNextItem()
    },
    async fetchNextItem() { .... } /* unmodified */
}

This can be slightly inconvenient if there are many asynchronous methods of which we use the return value.
I think this might become more and more common as people start understanding and using async/await more and more.

Initial context: I have a very specific use case of a vuejs<->python bridge that makes (among other things) all the python-written method callable from vuejs, but as the call goes through websockets, all methods end up async. https://github.com/twitwi/vuejs-python

What does the proposed API look like?

I'd suggest a ".async" modifier that would allow for "await" in the event handler snippet.
For the example above, it would be written as:

<span @click.async=" accumulator += await fetchNextItem() ">do it</span>

(this is probably useful for all types of events, not only click)

discussion feature request

Most helpful comment

I don't think it's worth adding another modifier that only serves a very few uses cases: there are not many cases where the code is still readable when doing an await inside an event handler in the html. You don't need to create a method, you should be able to do:

<span @click=" async () => accumulator += await fetchNextItem() ">do it</span>

You could also create your own function helpers that are accessible globally like asyncAdd:

<span @click=" asyncAdd(accumulator, fetchNextItem())">do it</span>

which ends up being shorter than the proposal.

Let's wait for more feedback on this

All 6 comments

I don't think it's worth adding another modifier that only serves a very few uses cases: there are not many cases where the code is still readable when doing an await inside an event handler in the html. You don't need to create a method, you should be able to do:

<span @click=" async () => accumulator += await fetchNextItem() ">do it</span>

You could also create your own function helpers that are accessible globally like asyncAdd:

<span @click=" asyncAdd(accumulator, fetchNextItem())">do it</span>

which ends up being shorter than the proposal.

Let's wait for more feedback on this

Thanks for the reply.
I like the first workaround, I'd give it a try

:+1:
For some reason, I needed to add some parentheses around it, but it works well.
For the record, I give the result here.

For the example above, this yields:
~vue
do it
~

For my use case (with affecting an attribute), this gives:
~vue
fetch
~

Or, alternatively, inspired by the second suggestion:

~vue
fetch
~

~javascript
methods: {
async asyncSet (attr, asyncVal) {
this.$set(this, attr, await asyncVal)
},
}
~

Thanks again for the workarounds.

@posva it looks like the parser doesn't understand async function expressions. Here's the compiler output:

function render() {
  with(this) {
    return _c('span', {
      on: {
        "click": function ($event) {
          async () => accumulator += await fetchNextItem()
        }
      }
    }, [_v("do it")])
  }
}

async inline function epxression demo

It appears to nest the entire string inside a normal function. Should this issue be re-purposed or create a new one?

I'm guessing the expected output should be:

function render() {
  with(this) {
    return _c('span', {
      on: {
        "click": async () => accumulator += await fetchNextItem()
      }
    }, [_v("do it")])
  }
}

@sirlancelot you are right, I adapted the compiler to allow it: https://github.com/vuejs/vue/pull/10361

This works for me:
@input="(async function(){myVariable= await _queryVals($event)})()"
but this failed:
@input="(async ()=>{myVariable= await _queryVals($event)})()"

Syntax Error: SyntaxError: await is a reserved word

It appears I can't use await inside an arrow function inside of an inline event handler.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

robertleeplummerjr picture robertleeplummerjr  Â·  3Comments

lmnsg picture lmnsg  Â·  3Comments

bfis picture bfis  Â·  3Comments

loki0609 picture loki0609  Â·  3Comments

gkiely picture gkiely  Â·  3Comments