question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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

See original GitHub issue

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.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
loilocommented, Jul 2, 2018

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.

1reaction
loilocommented, Jul 2, 2018

Only if you didn’t tell me and I didn’t know. 🙈 Which is pretty contrary to using it though. 😁

Read more comments on GitHub >

github_iconTop Results From Across the Web

JavaScript - Return promise AND/OR call callback?
Your function is always promise-based, also in the fact that it always returns a promise. The caller is simply free to ignore that....
Read more >
Promise - The Modern JavaScript Tutorial
Any state change is final. All further calls of resolve and reject are ignored: let promise = new Promise(function(resolve, reject) { resolve(" ...
Read more >
Understanding JavaScript Promises - DigitalOcean
Callbacks are a function you call when you get the return result. Let's modify the previous example to accept a callback. // add...
Read more >
AngularJs and Promises with the $http Service - Rick Strahl
The AngularJs $http object returns custom promises which can be ... This provides the albums collection to the .success() callback and we ...
Read more >
Node.js Async Best Practices & Avoiding the Callback Hell
We just wrap the original callback-based function in a promise, and then reject or resolve based on the result of the operation. Easy...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found