简体   繁体   中英

Waiting for array element to exist before pushing data

I have an array of objects like such:

var arr = [{
'timestamp' : 1,
},{
'timestamp' : 2,
},{
'timestamp' : 3,
},{
...
}];

Where I generate and push new objects to arr with a timer function:

this.state.labelTimer = window.setInterval(function () {
     addObjectToArr(timeStamp);
}, 1000);

Things get a little hairy, as I also have a WebSocket implementation using Laravel Echo that modifies properties of objects in arr :

// This method gets called whenever the WebSocket receives incoming data

Echo.channel('testChannel')
     // we have detected incoming data
    .listen('dataTrigger', (e) => {
     // modify the object at some array index
     modifyObjectInArr(e.data);
});

And the modifyObjectInArr(data) function appends a property to an object in the array like such:

arr[data.timestamp].someProperty = "something"

It is worth noting that I can have multiple requests coming in for the same timestamp, resulting in objects that look like this:

var arr= [{
'timestamp' : 1,
'val_1' : 12, // originating from one websocket call
'val_2' : 13 // originating from another websocket call
}];

It seems that on occasion, the WebSocket will attempt to modify the objects at arr[data.timestamp] before the element is pushed to the array via the function with the timer. Is there a good way to wait until the array has an element at the desired index (I cannot simply check to see if it already exists, and if not, push it -- it must be generated by the timer in this particular problem) and then push the incoming data from the WebSocket?

You could use the lazy instantiation pattern:

var arr = [];

function getDataFrame(timeStamp) {
  // Gets existing or creates new object
  return arr[timeStamp] || (arr[timeStamp] = { timestamp: timeStamp });
}

function modifyObjectInArr(data) {
   getDataFrame(data.timestamp).someProperty = 'something';
}

this.state.labelTimer = window.setInterval(function () {
  getDataFrame(timeStamp);
}, 1000);

That way, there's no race condition whether the interval callbacks or web socket callbacks try to manipulate the data first.

A coworker and I built something to solve a similar problem - in our case we wanted to wait until an array had reached a specific length. This is mostly used for testing (wait until we get X events then check them).

https://www.npmjs.com/package/awaitable-array

But it's basically a replacement for an array:

You can create an "AwaitableArray()" instead and push your items to it and wait for length:

let arr = new AwaitableArray();

setInterval(() => arr.push("test"), 500);

// This waits until 2 items have been pushed to the array.
await arr.untilLength(2);

So you could create this awaitable array instead of a regular array and wait until that index is hit.

It's pretty basic atm - doesn't support pop - just waiting for pushes up to that index but you could extend it pretty easily to do just about anything you need:

https://github.com/WakeskaterX/awaitable-array

It just uses proxy to intercept requests - I'd be leery of using it in high traffic environments I do not know what performance impacts it might have it's been a testing tool only for us but we use this quite extensively for these kinds of situations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM