Issue with handling multiple messages in WebSocket responses as Promises

In my web project using angularjs, I have the task of downloading data every second via a WebSocket. However, I encounter issues with handling multiple requests of different types. Although I utilize Promises to structure the requests, sometimes the responses end up in the wrong function. To provide an example:

I've created a service responsible for making the requests and receiving Promise-based results.

socketService.$inject = [];
function socketService(){
    let service = this;

    let server = new WebSocket('ws://localhost:8090');
    let isOpen = false;

    server.onopen = function(){
        isOpen = true;
    };

    server.onerror = function(){
      //TODO handle error
    };

    service.sendRequest = function(action, data){
        return new Promise(function (resolve, reject) {

            if (isOpen) {
                server.send(encodeRequest(action, data));
                server.onmessage = function (message) {
                    resolve(JSON.parse(message.data));
                }
            }

            server.onopen = function () {
                server.send(encodeRequest(action, data));
                server.onmessage = function(message) {
                    resolve(JSON.parse(message.data));
                    isOpen = true;
                }
            };

            server.onerror = function (error) {
                reject(error);
            }
        })
    };

}

This is how I use it:

socketService.sendRequest('get_events', {})
  .then(function (response) {
      //DO SOMETHING WITH THE RESPONSE
      return socketService.sendRequest('get_history', {
          fromDate: value,
          toDate  : value,
          tag     : value,
          event   : value
      })
  })
  .then(function (response) {
      //DO SOMETHING WITH THE RESPONSE
  });

The issue arises when I make concurrent requests. If I trigger multiple requests within seconds and then introduce a new request at the same time, the responses become mixed up. It seems that if I send a request and before its response, another request is made, the first response goes to the second request.

I am puzzled by this behavior as I'm returning a new Promise each time, which should associate the response with the correct Promise instead of mixing them up.

While I've learned that a resolved Promise cannot be reused (it will return the last result), I continuously create new ones. Can someone shed light on what might be happening and suggest potential solutions?

Answer №1

To ensure each response is matched to the correct request, it's important to assign a unique ID to each message. Before delving into coding this, consider exploring json rpc 2.0, a standard with various javascript implementations that can simplify this process for you. A reliable option I've had success with is https://github.com/jershell/simple-jsonrpc-js

You mentioned your concerns about Promise code not functioning as expected. The thing is, Promises might not always work as anticipated. Your Promise code modifies the server's callback methods (onOpen, onMessage, etc.) to trigger the promise's "resolve" function. However, since there's only one server despite having multiple promises, each new Promise just assigns the server's callback methods to a fresh resolve function.

But... instead of going through all that trouble, consider leveraging solutions that have already been developed, like JSON RPC 2.0.

Duncan

Answer №2

I encountered the same challenges with WebSocket messages behaving like events. To address this issue, I developed a library that enables writing Promise-based functions for sending and receiving messages.

Check out my library here!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Receiving the outcome of an asynchronous function in JavaScript

async function retrieveKey() { try { var key = await dec.awsDecrypt('dev-frontend') return key; } catch(err) { } } //calling the function const result = retrieveKey() In the code snippet above, there is an asynchronous ...

Guide to implementing a personalized filter in AngularJS 1.6

I am struggling with injecting a custom filter, status, into my component. Below is the code for my component: function ClaimsListController(dpClaimsListService) { var ctrl = this; ctrl.claims = null; ctrl.searchCriterion = null; ctrl.l ...

When I attempt to post to my restify API, I am receiving an error message stating that the "name_of_the_field" path is required

I have encountered an issue while trying to send data to my REST API using Angularjs and Restify. Despite filling out the form and submitting it, I am receiving a console error from the server (node and restify) stating that the field is required even thou ...

VueRouter child route with trailing slash after default

VueRouter automatically includes a trailing slash before the child route's path. Consider this example of a route configuration: const routes = [ path: '/home', components: { default: HomeBase }, children: [ ...

Error: The OOP class value for translateX in the Web Animation API is returning as undefined

I'm currently working on a basic animation project using JavaScript. I have utilized the Animation class from the Web Animation API. My goal is to create multiple instances of this class in order to animate different elements with varying values and r ...

Shopping cart development using AngularJS with Ionic Framework

I am currently in the process of developing an online marketplace app. I have successfully implemented the shopping cart functionality, although I am unsure of how to integrate it into my Ionic/AngularJS platform. Are there any resources or solutions avail ...

creating styles for css elements using equations

I am curious about defining CSS element dimensions before they are rendered without using offset and jQuery. Is it possible to echo PHP into the width/height or position values? For example: <?php $width = 290px; $altwidth = 290; ?> <style> ...

Adding elements to an array using JavaScript

What is the correct way to add new values to an array like this? json = {"awesome":"45.22","supercool":"9876"} I attempted json.push("amazingness":"45.22");, but unfortunately it was not successful. ...

Three.js- I am having trouble with my shadow rendering, as lots of black lines are appearing everywhere instead of the shadows showing

Having recently delved into Three.js, I managed to add shadows to my model with the help of some knowledgeable individuals. However, upon the light hitting the model, numerous lines appear, causing me to question whether it's due to my poor modeling s ...

unable to decipher a JSON file obtained from Instagram

I have been working on a project that involves parsing a JSON file obtained from the Instagram API. However, I am facing an issue where I can parse the data but I cannot read it properly in my code: <!DOCTYPE html> <html> <head> <meta ...

Ensure at least one checkbox is selected by using jQuery validation

I wrote the code below to select multiple checkboxes and validate that at least one checkbox is selected. The data submission to the database works if I remove onsubmit="return validate_form()". However, I want to ensure that at least one checkbox is selec ...

Using an id as the attribute value for a React ref

I have a question about referencing DOM nodes in a component. Currently, I am able to get the nodes and children using the following code: export class AutoScrollTarget extends React.Component { constructor(props) { super(props); this ...

Using React to fetch data and then mapping it inside a function

I am facing an issue where I need to make a request for each item in the MAP, but I want to ensure that I wait for the response before moving on to the next object. Currently, my code is sending out all the requests simultaneously, causing the Backend to c ...

Having trouble obtaining outcomes from Cloud Code in Parse

After struggling with this issue for quite some time, I have reached a point where I feel the need to seek help. I am working on a cloud code function that is supposed to retrieve a list of categories along with their respective products. Each category con ...

The ajax request does not support this method (the keydown event is only active during debugging)

I've encountered a strange issue with an AJAX request. The server-side code in app.py: #### app.py from flask import Flask, request, render_template app = Flask(__name__) app.debug = True @app.route("/myajax", methods=['GET', ...

I'm having trouble with my AngularJS Spinner directive

Check out this simple directive I created to display a spinner on my button while something is happening remotely: http://plnkr.co/edit/rAJ4X7A3iidmqUD2M63A?p=preview Here's the html: <!DOCTYPE html> <html ng-app="app"> <head> ...

If the condition is met with the presence of X in the string, execute one action; otherwise, proceed with

Currently, my code successfully grabs the results: module.exports = async function grabResult(page) { const message = await page.$eval( 'div > div:nth-child(2)', (el) => el.innerText ); const username = await page.$eval( ...

What is the process for transferring a file's contents to my server?

I am currently working on allowing users to import an OPML file that I parse server-side in my Rails application. However, I am facing difficulties as it appears that my server is not receiving the information correctly (neither the success nor error funct ...

Tips for creating a mobile-friendly 30-day chart with chart.js

I created a chart displaying 30 days of absence data using the react-chartjs-2 library, but it is not responsive. How can I make it responsive? Here's how it appears on a laptop: chart on laptop And this is how it looks on mobile: chart on mobile T ...

Vertical scrollbar in iframe unexpectedly appears immediately after the submit button is pressed

I have designed a contact form that is displayed in an iframe within an overlay div. I have carefully adjusted the dimensions of this div to ensure that there are no scrollbars visible when the form initially appears. However, after filling out the form an ...