Skip to content

Return a Promise from vm.$once() with callback omitted #8444

Closed
@loilo

Description

@loilo

What problem does this feature solve?

Deferring a process to wait for a signal currently is a little bit tedious. Signals are usually carried as events and reacted to via vm.$on() resp. vm.$once().
Now that we have async/await, we could improve developer ergonomy greatly by having a Promise returned from vm.$once() – similar to vm.$nextTick().

What does the proposed API look like?

Note: I've omitted any additional boilerplate from the examples below. Please assume each example is executed in the context of an async Vue method.

So what we'd want to do is deferring the execution of our code until the signal event is emitted by our Vue instance.

A quick recap how this could currently be done:

// Old School: Use a callback
this.$once('signal', (...payload) => {
  // Could lead to some callback hell though
})

// Alternatively: Wrap in a Promise
const payload = await new Promise(resolve =>
  this.$once('signal', (...payload) => resolve(payload))
)
// However, this is an awful lot of boilerplate, and it gets incredibly messy if we'd want to await various different signals

How this would look with the proposed change:

// The following $once() call got no callback parameter, so it returns a Promise (which resolves to an array of the event parameters)
const payload = await this.$once('signal')

// This is effectively equivalent to the Promise wrap example from above

// Bonus: Multiple different signals
const payloads = await Promise.all([
  this.$once('signal-1'),
  this.$once('signal-2'),
  this.$once('signal-3')
])

Note that a Promise would only be returned if the callback parameter was omitted, so the following still works:

// Inside some method
this
  .$once('signal', (...payload) => {
    // This $once() call still returns the Vue instance, no change to current behaviour
  })
  .$on('other-event', () => {
    // That means we can still chain event listeners and avoid a practical breaking change
  })

While this is technically a breaking change, it's a rather soft one since previously using the $once() method without a callback had no use case.

To me, this change sounds like pretty low-hanging fruit. I'd love to hear your opinion regarding this idea.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions