joewalnes / reconnecting-websocket

A small decorator for the JavaScript WebSocket API that automatically reconnects
MIT License
4.21k stars 970 forks source link

How to use "ws.once" with this library? #121

Closed regisfaria closed 2 years ago

regisfaria commented 2 years ago

Hello!

I adopted this package when I was needing to have my WS connections restarted if they disconnect. It worked perfectly in my case, since I was using this to follow up crypto-currencies value changes.

Now I wish to also have a channel open, using this package, but I lack one functionality that my code needs, which is the method: ".once("message",() => {})". I use this to send crypto orders and get their respective message right after.

Anyone have ideas on how to achieve that?

I need to follow one pipeline of: send data to ws server -> get the message and send new data -> get message and send -> ... and so on until I achieve the end(I usually do this around 4 times), which is a variable full of specific data for my app.

Searching through the "reconnecting-websocket" lib I found no "once" method.

I really appreciate if anyone can help me.

makyen commented 2 years ago

Something like .once() is merely a convenience function that puts a wrapper around whatever listener you're adding which removes itself and your listener after a single event. As long as you have a way to add listeners and remove listeners, then there is absolutely no reason you can't implement a similar feature within your event listener, or even an actual .once(), yourself. There's no need to push something like that down into a low level implementation.

regisfaria commented 2 years ago

@makyen I see, indeed it make sense. Can you share an example of creating and removing the same listener? That would help a lot.

My goal is to achieve a way to send data and right after that catch the message the WS server sent to me, repeatedly, until I get to a point of stop, which is my data with everything I need.

makyen commented 2 years ago

Assuming you're targeting semi-recent browsers, then you can just use {once: true} as an option to your call to .addEventListener(). {once: true} is a convenience option which was added to Chrome and Firefox in 2016.

If you need to support even older browsers, then you probably should take a look at "How can I add an event for a one time click to a function?", which has answers showing how to manually use .addEventListener() and .removeEventListener() to accomplish the same thing. If you need to support IE < 9, you'll need to search around for specific examples, as IE < 9 uses .attachEvent() instead of .addEventListener().

regisfaria commented 2 years ago

@makyen I guess I forgot to say that I'm using this in a backend server.

As you can see in the below image, there is no such way to add {once: true} to the event listener, if there was, I would probably not having this kind of trouble =/ image

makyen commented 2 years ago

@regisfaria You haven't mentioned the actual environment in which you are running your code, so there's no way for me to know that or address any issues. There's also no way for me to determine if your IDE is providing you with the actual signature for the method being called, which it may or may not be accurately displaying (i.e. such things are wrong from time to time, don't assume 100% accuracy).

If you're using Node.js, then it looks like {once: true} was added in 14.5.0, which was released on 2020-06-30. If you're using Deno, then {once: true} was added in 1.0, which was released on 2020-05-13. Beyond those, I don't have much information.

Reconnecting-websocket merely uses .bind() to use all features of the underlying event features:

        // Expose the API required by EventTarget

        this.addEventListener = eventTarget.addEventListener.bind(eventTarget);
        this.removeEventListener = eventTarget.removeEventListener.bind(eventTarget);
        this.dispatchEvent = eventTarget.dispatchEvent.bind(eventTarget);

So, if the {once: true} feature is available in the environment you're running in will depend entirely on that environment. Using {once: true} definitely works with reconnecting-websocket in browsers.

As I mentioned, {once: true} is just a convenience. It doesn't add anything which can't be done with only .addEventListener() and .removeEventListener(). The other answers on the question to which I linked give multiple examples of how you can accomplish this with just those methods and without .once() or {once: true}.

Overall, I wouldn't support doing any work within reconnecting-websocket to polyfill support for some type of once feature, given that it already works if available in the underlying environment. If it really isn't available in the environment you're using and upgrading the environment isn't an option, then you could add/load a polyfill (seems like overfill), or just use a few lines of code to implement the feature within the event handlers where you're wanting to use it.

regisfaria commented 2 years ago

@makyen Thank you much for the complete response, sir!

To currently solve my issue, as I had to deliver it fast, I've implemented my own reconnecting strategy using WebSocket(ws package). Although I will look into it and see if is possible to add what you've just mentioned, so I can keep all in one standard.

Thanks again! ✌🏻