Updating a common global data-structure using multiple promises in Javascript - javascript

Consider the following code:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
var globalList = Array();
globalList[0] = "Test";
globalList[1] = "Another Test";
async function coreFunc(promiseName, sleepTime) {
console.log("Started CoreFunc: "+promiseName);
var localList = globalList;
console.log("Length of local array: "+localList.length);
console.log("Length of global array: "+globalList.length);
if (promiseName != "Promise0") {
for (i = 0; i < localList.length; i++) {
console.log(localList[i]);
}
}
if (promiseName == "Promise0") {
var testList = new Array();
testList[0] = "Changed";
globalList = testList;
}
await sleep(sleepTime);
console.log("Length of local array: "+localList.length);
console.log("Length of global array: "+globalList.length);
console.log("Done with CoreFunc: "+promiseName);
}
async function testMultiplePromises() {
var thArray = Array();
for (i = 0; i < 4; i++) {
var pr = new Promise(resolve => coreFunc("Promise" + i, 3000));
thArray[i] = pr;
}
for (i = 0; i < thArray.length; i++) {
await thArray[i];
}
}
globalList is an array that is global. When the above code is invoked like the following:
await testMultiplePromises();
The code goes into an infinite loop. The problem is definitely in the following segment where I am reinitializing the global variable to some different array:
if (promiseName == "Promise0") {
var testList = new Array();
testList[0] = "Changed";
globalList = testList;
}
Is there a way to copy the global datastructure to a local variable without leading to index out of bounds or infinite loop kind of issues? The following code is definitely not doing the job:
var localList = globalList;
What should be done in order to ensure that the Promises either get the older array or get the newer array? To rephrase, how do I make sure the code inside coreFunc (Promise0) that changes the global data structure is protected?

Infinite loop is caused by global i variable on for loops. You should type it like this
...
for (var i = 0; i < localList.length; i++) {
...
for (var i = 0; i < 4; i++) {
...
for (var i = 0; i < thArray.length; i++) {
...
To "protect" array you can just copy it like this
var localList = JSON.parse(JSON.stringify(globalList));

There are a few problems in your code.
var globalList = Array(); - missing the new keyword here.
var localList = globalList; - this does NOT create a copy of the Array, it just creates a reference to the outer array. So whatever you change in localList will also be changed in globalList. Try this: var localList = [...globalList];. This creates a (shallow) copy.
globalList = testList; - same here.
A good read about pass by value vs. pass by reference can be found here.

Related

Adding dynamic named Javascript object to an array with a for loop

Wondering if it is possible to use a loop to add dynamically named objects to an array, so I don't need to repeat the "push" on an array. Tks !!
let _objA0 = { "name":"regionId", "value":"myRegion" };
let _objA1 = { "name":"vdcId", "value":"myId" };
let _objA2 ... _objA100
let test = []
test.push(_objA0)
test.push(_objA1)
...
test.push(_objA100)
I guess it's the right time to use eval
let test = [];
for(let i = 0; i <= 100; i++) {
test.push(eval(`_objA${i}`));
}
You can access variables (with var keyword) by window object , try this:
var _objA0 = { "name":"regionId", "value":"myRegion" };
var _objA1 = { "name":"vdcId", "value":"myId" };
let test = [];
for(let i = 0; i < 2; i++){
test.push(window['_objA' + i]);
}
console.log(test)

Javascript foreach not executing for all objects

I currently have an object that adds itself to an array whenever a new one is created. Eventually, I want to remove all of the references in the array so I can add new ones.
I've created an object method (this.removeFromArray()) that looks for itself in the array and splices itself out. removeAll() runs a for loop that makes each object in the array run removeFromArray(), so I expect that when I try to read out the items in the array, I should get nothing.
Instead, depending on the amount of objects created, I get one or two left behind. How can I fix this and have all objects in the array cleared out?
var objArray = [];
function obj(name) {
objArray.push(this);
console.log("Created "+name);
this.name = name;
this.removeFromArray = function() {
objArray.splice(
objArray.findIndex(function(e) {
return e == this;
}),
1
);
}
}
function removeAll() {
for (var i = 0; i <= objArray.length - 1; i++) {
objArray[i].removeFromArray();
}
}
var foo = new obj("foo");
var bar = new obj("bar");
var cat = new obj("cat");
var dog = new obj("dog");
var bird = new obj("bird");
removeAll();
for (var i = 0; i <= objArray.length-1; i++) { //Check the values in the array for leftovers
console.log(objArray[i].name);
}
//Expected nothing in the console but the creation messages, got foo and bar instead
If you want to simply delete all the created object, edit removeAll() function like below:
Note that you have to create a variable for objArray.length, not directly put the objArray.length to for() loop.
function removeAll() {
var len = objArray.length;
for (var i = 0; i <= len - 1; i++) {
objArray.splice(0,1);
}
}
better way to achieve this would be to utilize inheritance through prototype. it is better than creating a function inside the constructor object.
var objArray = [];
function Obj(name) {
this.name = name;
objArray.push(this);
}
Obj.prototype.removeFromArray = function() {
var i = -1,
len = objArray.length,
removed = null;
while (++i < len) {
if (objArray[i] === this) {
removed = objArray.splice(i, 1);
removed = null; //nullify to free memory, though not that necessary
break;
}
}
};
Obj.prototype.removeAll = function() {
var len = objArray.length,
removed = null;
//note that i started from the last item to remove to avoid index out of range error
while (--len >= 0) {
removed = objArray.splice(len, 1);
removed = null; //nullify to free memory, though not that necessary
}
};

js rewrite previous elements in loop

I want to push elements to array in loop but when my method returns a value, it always rewrites every element of array(probably returned value refers to the same object). I'm stuck with this problem for one day and I can't understand where is the problem because I've always tried to create new objects and assign them to 'var' not to 'let' variables. Here is my code:
setSeason(competitions, unions) {
var categories = this.sortCategories(competitions);
var unionsByCategories = new Array();
let k = 0;
for (; k < categories.length; k++) {
unionsByCategories[k] = this.assignCompetitionsToUnions(unions[0], categories[k]);
}
this.setState({categories: unionsByCategories, refreshing: false})
}
and
assignCompetitionsToUnions(unions1, competitions) {
var unions2 = this.alignUnions(unions1);
let tempUnions = [];
for (var i = 0; i < unions2.length; i++) {
var tempUnionsCompetitions = new Array();
var tempSubsCompetitions = new Array();
if (Globals.checkNested(unions2[i], 'union')) {
tempUnionsCompetitions = unions2[i].union;
tempUnionsCompetitions['competitions'] = this.getCompetitionsById(unions2[i].union.id, competitions);
}
if (Globals.checkNested(unions2[i], 'subs')) {
for (var j = 0; j < unions2[i].subs.length; j++) {
if (Globals.checkNested(unions2[i].subs[j], 'union')) {
tempSubsCompetitions[tempSubsCompetitions.length] = {union: unions2[i].subs[j].union};
tempSubsCompetitions[tempSubsCompetitions.length - 1]['union']['competitions'] =
this.getCompetitionsById(unions2[i].subs[j].union.id, competitions)
}
}
}
tempUnions.push({union: tempUnionsCompetitions, subs: tempSubsCompetitions});
}
return tempUnions;
}
Many thanks for any help.
Answer updated by #Knipe request
alignUnions(unions3) {
let newUnions = unions3.subs;
newUnions = [{union: unions3.union}].concat(newUnions);
return newUnions.slice(0, newUnions.length - 1);
}
getCompetitionsById(id, competitions) {
let tempCompetitions = [];
for (let i = 0; i < competitions.length; i++) {
if (competitions[i].union.id === id) {
tempCompetitions.push(competitions[i]);
}
}
return tempCompetitions;
}
sortCategories(competitions) {
if (competitions.length === 0) return [];
let categories = [];
categories.push(competitions.filter((item) => {
return item.category === 'ADULTS' && item.sex === 'M'
}));
categories.push(competitions.filter((item) => {
return item.category === 'ADULTS' && item.sex === 'F'
}));
categories.push(competitions.filter((item) => {
return item.category !== 'ADULTS'
}));
return categories;
}
it always rewrites every element of array(probably returned value
refers to the same object).
You are probably unintended mutating the content of the source array. I would recommend creating a copy of the array.
This is example of array mutation.
let array1 = [1,2,3];
let array2 = array1;
array2[0] = 4; // oops, now the content of array1 is [4,2,3]
To avoid mutating the source array you can create a copy of it
let array1 = [1,2,3];
let array2 = array1.slice();
array2[0] = 4; // the content of array1 is still the same [1,2,3]
I've always tried to create new objects and assign them to 'var' not
to 'let' variables.
Using let/var will not prevent from rewrites. Creating new object with new Array() will not prevent rewrites.
It's hard to read where the bug is exactly from your code and description but you could try to avoid passing an array by reference and instead create a copy and pass the copy in function calls.
this.assignCompetitionsToUnions(unions[0].slice(), categories[k])
This is a shallow copy example, you might need to apply deep copy to make it work for your case.

javascript - create new (global) objects with names from array

i am trying to create new Objects with names out of an array.
Without an array i would do:
var object_bruno = new Object();
var object_carlos = new Object();
var object_luci = new Object();
so i will end up with 3 new Objects. But why wont we do that with an loop, which makes it more easy to adde some more Objects later. So i ttried:
// an array full of object names
var obj_arr = [ "object_bruno", "object_carlos", "object_luci"];
// Method one:
for (x in obj_arr) {
alert(obj_arr[x]); // right names shown
var obj_arr[x] = new Object(); //syntax error, dosent work??
};
// Method two:
obj_arr.forEach(function(func_name) {
alert(func_name); // right names
var func_name = new Object(); // no objects are created ???
});
basicly i would prefer to use Method two. i like it because i can fill them late the same way? hopefuly? Any ideas what wents wrong?
You can just loop over the array and assign a new Object to each of the items , like this:
for (var i = 0, l = obj_arr.length; i < l; i++) {
obj_arr[i] = {};
}
UPDATE
You can also do it in this way by applying properties to the global object, for example window:
var people = [ "object_bruno", "object_carlos", "object_luci"];
for (var i = 0, l = people.length; i < l; i++) {
global[people[i]] = {};
}
Using this solution makes the objects global, so you can use them like object_bruno.
Another improvement can be the usage of computed propertiey names of ECMAScript 2015:
var people = [ "bruno", "carlos", "luci"], prefix = 'object_';
for (var i = 0, l = people.length; i < l; i++) {
global[prefix + people[i]] = {};
}
This allows to have more meaningful array.
Note, the global can be the window object in browsers or global object in NodeJS, or perhaps something else in other environments.
Because you are creating a new variable by declaring
obj_arr.forEach(function(func_name) {
alert(func_name); // right names
var func_name = new Object(); // no objects are created ???
});
try this
obj_arr.forEach(function(func_name) {
alert(func_name); // right names
func_name = new Object(); // no objects are created ???
});
var obj_arr = [ "object_bruno", "object_carlos", "object_luci"];
obj_arr.forEach(function(func_name, index, arr) {
arr[index] = {};
});

Can't pass arrays in multidimensional array to other function using setInterval

I have a multidimensional array named "thisIsMyContainerArray" that holds content of two other arrays. What I'm trying to do is check each item in the "thisIsMyContainerArray" array and log each item (in this case, two other arrays) from that array separately in the console, and do so every 5 seconds. So far I have the following code:
var thisIsMyContainerArray = new Array();
var thisIsMyArray1 = new Array('val1', 'val2', 'val3', 'val4');
var thisIsMyArray2 = new Array('valA', 'valB', 'valC', 'valD');
thisIsMyContainerArray.push(thisIsMyArray1, thisIsMyArray2);
for (var i = 0; i < thisIsMyContainerArray.length; i++) {
var t1 = setInterval(tester,5000);
function tester() {
console.log(thisIsMyContainerArray[i]);
}
}
And I always get the following output in my console, every 5 seconds:
["val1", "val2", "val3", "val4"]
["val1", "val2", "val3", "val4"]
This is my desired result, I need to see this in the console instead of the output I mentioned earlier:
["val1", "val2", "val3", "val4"]
["valA", "valB", "valC", "valD"]
Any help would be greatly appreciated since I've been stuck on this for a few hours now and I just can't figure it out. :( I tried passing it to the tester function but then it turns out as "undefined".
try this - you should be able to get this working if it is not at the moment..
var thisIsMyContainerArray = new Array();
var thisIsMyArray1 = new Array('val1', 'val2', 'val3', 'val4');
var thisIsMyArray2 = new Array('valA', 'valB', 'valC', 'valD');
thisIsMyContainerArray.push(thisIsMyArray1, thisIsMyArray2);
var t1 = setInterval(tester,5000);
function tester()
{
for (var i = 0; i < thisIsMyContainerArray.length; i++)
{
console.log(thisIsMyContainerArray[i]);
}
}
If I test this code in a clean environment, all it outputs is undefined, so its probably because the i variable isn't passed along, nor contained within a closure scope. Basically, there is an i variable somewhere in the global namespace set to 0, which is the one used.
Also, I'm not sure if you're doing more with the t1 variable, but its being reset at every loop, so you're going to get rogue intervals.
If the logging is all you're after, I'd do this:
var thisIsMyContainerArray = new Array();
var thisIsMyArray1 = new Array('val1', 'val2', 'val3', 'val4');
var thisIsMyArray2 = new Array('valA', 'valB', 'valC', 'valD');
thisIsMyContainerArray.push(thisIsMyArray1, thisIsMyArray2);
var t1 = setInterval(tester,5000);
function tester() {
for (var i = 0; i < thisIsMyContainerArray.length; i++) {
console.log(thisIsMyContainerArray[i]);
}
}
If this is just a simplified example and you need the original structure with a loop and setting multiple intervals for each array, try this:
var thisIsMyContainerArray = new Array();
var thisIsMyArray1 = new Array('val1', 'val2', 'val3', 'val4');
var thisIsMyArray2 = new Array('valA', 'valB', 'valC', 'valD');
thisIsMyContainerArray.push(thisIsMyArray1, thisIsMyArray2);
function tester(index) {
console.log(thisIsMyContainerArray[index]);
setTimeout(function() {
tester(index);
}, 5000);
}
for (var i = 0; i < thisIsMyContainerArray.length; i++) {
tester(i);
}

Categories

Resources