Home » vue » Vue: From inside function, how to wait for another function to finish?

Vue: From inside function, how to wait for another function to finish?

Posted by: admin November 26, 2021 Leave a comment

Questions:

In the code below, when newFlow is true, I emit an event to the root of the app to fire GetIDFromNewFlow() . That functions makes an Axios request to get data from an endpoint and sets the response to a data instance called IDDataPiece. The emitcheckout event triggers a function in the root to handle the checkout and it’s dependent on that IDDataPiece that is set once the response of the first emitted event comes back but the problem is it’s coming back too late so the 2nd emitted event is hung up waiting.
I thought the setTimeout would resolve it, and it does at times, but it’s inconsistent and I’d rather not make the setTimeout a large amount of time just to be safe because that feels sloppy.

checkout: function(card) {

    if (this.newFlow) {

        this.$emit('emitgetidfromnewflow');
    }
    setTimeout(() => {
        let orderId = null;

        let data = {
            cardId: cardId,
            orderId: orderId
        }

        this.$emit('emitcheckout', data)
    }, 2000)

},
Answers:

I think you may be misusing events.

An event (in general) is a way of notifying the outside world that something has happened to you. As an example consider native browser DOM events, things like click and blur. It might be that these events are completely ignored but they provide the opportunity for code to run when something happens to a DOM element.

When emitting events from a Vue component the idea is the same. Something has happened to the component (or is about to happen to the component) that might be of interest elsewhere.

It’s not uncommon for a component to need to do some stuff internally as well as firing an event. That’s fine, a component should handle whatever responsibilities it has and then fire an event to let external observers do their thing. The component is not responsible for what those external observers do, that’s their problem.

It’s important to appreciate responsibilities here. When a component emits an event it is not responsible for what the observer does with that event. The observers might not even exist.

So, for example, if you’ve got a button emitting a click event, the button’s responsibility ends with emitting the event. If nothing is listening for that event then nothing will happen, which is almost certainly a bug. But that bug isn’t the button’s problem.

Events shouldn’t be used in place of method calls. If a component is responsible for ensuring that a specific thing happens then it should call a method to make that happen. Events should not be emitted to tell something else to do something, they should be used to notify observers that something has happened to it. This is nuanced as in a lot of cases a component is only used in one place and an event only has one listener, so the event seems equivalent to a method call.

So, going back to the code in the question, it would seem that emitgetidfromnewflow is not a proper event in the sense that I have described above. That seems to be a workaround to make sure a particular method gets called. Perhaps this is a legitimate event from the perspective of this component but the name implies otherwise.

The emitcheckout event on the other hand does seem to be a proper event. It’s something that has happened to this component. Obviously the action of checking out is not yet complete from a user’s perspective but as far as this component’s responsibility goes it’s done with it. Whatever else might be required is not its problem, that’s for any observers to handle.

So, to get your code working, the first step is to establish what the real events are here. Making sure those events are handled correctly is not this component’s responsibility, so the timer should definitely go. Whatever is listening for the events will need to keep track of what’s going on and whether one thing needs to wait for another. Chances are there’ll be some promises involved and you’ll need to wait for one promise to resolve before dealing with the second event.

If you think that responsibility should remain within this component then the first event is probably not appropriate. Instead make a method call. Most likely that method call would return a promise so you can then wait for that before emitting the real event.

As a final thought, you may want to consider using Vuex rather than getting tied into knots with events on a root.