Return a Promise from vm.$once() with callback omitted
See original GitHub issueWhat 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.
Issue Analytics
- State:
- Created 5 years ago
- Comments:7 (3 by maintainers)
Top GitHub Comments
I’d like to humbly disagree.
While
$once
is called synchronously, its event’s origin is usually of asynchronous nature (via a user interaction). However I don’t even think Promises should be specific to async code. I’d say they are just as much about flow control and ergonomics, which makes them useful in pretty much all places where a one-time callback would be suitable.The point about not knowing if the Promise will ever resolve makes me feel uncomfortable as well, but I don’t think that’s a very rational objection. It’s not really different from a
$once
callback never being called.However, I think there’s no obligation for us to agree on that topic. Thanks for discussing this issue with me. 🙂
P.S.: FWIW, the Node.js team currently has basically the same discussion going on.
Only if you didn’t tell me and I didn’t know. 🙈 Which is pretty contrary to using it though. 😁