Javascript Closure inside loops - javascript

window.config = {
"Environments": [
"LH5",
"LH8",
"AMS"
],
"Clusters": [
4,
4,
4
]
};
Below is the promise object:
for (var i = 0; i < window.config.Environments.length; i++) {
for (var j = 1; j < window.config.Clusters[i] + 1; j++) {
promiseObj.physical[window.config.Environments[i] + "#Cluster" + j] = $http.get('http://url0/search?idc=' + window.config.Environments[i] + '&type=Physical&cluster=' + j).success(function(data) {
$scope.servers = data; // get data from json
countcores[window.config.Environments[i] + "#Cluster" + j] = 0;
countmemory[window.config.Environments[i] + "#Cluster" + j] = 0;
angular.forEach($scope.servers, function(item) {
countcores[window.config.Environments[i] + "#Cluster" + j] = parseInt(countcores[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.cores);
countmemory[window.config.Environments[i] + "#Cluster" + j] = parseInt(countmemory[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.memory);
});
});
promiseObj.virtual[window.config.Environments[i] + "#Cluster" + j] = $http.get('http://url/search?idc=' + window.config.Environments[i] + '&type=Virtual&cluster=' + j).success(function(data) {
$scope.servers = data; // get data from json
countvirtualcores[window.config.Environments[i] + "#Cluster" + j] = 0;
countvirtualmemory[window.config.Environments[i] + "#Cluster" + j] = 0;
angular.forEach($scope.servers, function(item) {
countvirtualcores[window.config.Environments[i] + "#Cluster" + j] = parseInt(countvirtualcores[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.cores);
countvirtualmemory[window.config.Environments[i] + "#Cluster" + j] = parseInt(countvirtualmemory[window.config.Environments[i] + "#Cluster" + j]) + parseInt(item.memory);
});
});
}
}
What appears to be happenning is that the loop is going quicker than the promise object and j is reaching 5 before the promise object and what is logged is
["undefined#Cluster5"] = 1280
What I'm expecting is
["LH5#Cluster1"] = somevalue;
["LH5#Cluster2"] = somevalue;
["LH5#Cluster3"] = somevalue;
["LH5#Cluster4"] = somevalue;
["LH8#Cluster1"] = somevalue;
["LH8#Cluster2"] = somevalue;
["LH8#Cluster3"] = somevalue;
["LH8#Cluster4"] = somevalue;
["AMS#Cluster1"] = somevalue;
["AMS#Cluster2"] = somevalue;
["AMS#Cluster3"] = somevalue;
["AMS#Cluster4"] = somevalue;
I have multiple promiseObjectives running in the same loop(s) - how does this work? I am aware of JavaScript closure inside loops – simple practical example - However this does not help me, I require further assistance.

The referenced URL was made to exemplify what you need to do and in a simple manner. The issue you are encountering is the same issue as the one referenced in the URL. You need to ensure that you are scoping your i & j variables for each function call. Therefore, you need closures around your success function that pass in the i & j variables to return the function that you wish to call when the success() is called for the $http.get() function.
I am not going to do the exact code but it would look somewhat similar to this:
$http.get('http://url').success(function(i,j){
return function (data){
//code stuff happens here
}
}(i,j));
This way the function(i,j){ ... }(i,j) is called and it then returns the actual function return function(data){} with the i & j variables properly scoped and having the values that they did when the function function(i,j){ ... }(i,j) was called.
**As a side note I would change the scoped varaible names from i & j to something more descriptive and less confusing

Related

Javascript - Using promise for post PHP, get undefined result

I'm a newbie in JS and have a little to no knowledge about asynchronous program and promise. I have a problem in getting result from post PHP as written in this code:
showModalLink = function(d, i) {
$('#myModalLabel').text(d.source.name + ' - ' + d.target.name);
$('#modalJum').text(d.jumlahlelangsama);
var lelang = d.daftarlelangsama.split(", ");
var lelangmodal = [];
var promises = [];
for (var i = 0; i < lelang.length; i++) {
querystring = "select pemenang from lelang where id = " + lelang[i];
console.log(querystring);
var queryobj = {
query: querystring
};
promises.push($.post('indikasi3modal.php', queryobj));
}
Promise.all(promises).then(function(results) {
if (results[i] == d.source.name) {
console.log("1");
lelangmodal.push(lelang[i] + " - dimenangkan oleh " + d.source.name);
console.log(lelangmodal);
}
else if (results[i] == d.target.name) {
console.log("2");
lelangmodal.push(lelang[i] + " - dimenangkan oleh " + d.target.name);
console.log(lelangmodal);
}
else {
console.log("3");
lelangmodal.push(lelang[i]);
console.log(lelangmodal);
}
$('#modalLelang').text(lelangmodal);
$('#myModal').modal('show');
});}
I have no idea why the results[i] return undefined inside then function loop. Any help (or alternative ways to solve this) appreciated. Thanks!
I have no idea why the results[i] return undefined inside then function loop.
Because you don't have a loop in the .then() function. So i has the value it had at the end of the loop that created all the promises, which is the number of promises that were created. But the indexes of results go from 0 to i-1.
Promise.all(promises).then(function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i] == d.source.name) {
console.log("1");
lelangmodal.push(lelang[i] + " - dimenangkan oleh " + d.source.name);
console.log(lelangmodal);
} else if (results[i] == d.target.name) {
console.log("2");
lelangmodal.push(lelang[i] + " - dimenangkan oleh " + d.target.name);
console.log(lelangmodal);
} else {
console.log("3");
lelangmodal.push(lelang[i]);
console.log(lelangmodal);
}
}
$('#modalLelang').text(lelangmodal);
$('#myModal').modal('show');
});

Second loop is not working

I´m running this test with nightwatch and I have a loop inside a loop, first one runs ok but it fails going inside 2nd loop.
I wrote a console.log and returns:
Number of links:[object Object]
This is my code:
What´s the reason for not entering in loop 2?
Thanks in advance.
.execute(
function() {
return document.querySelectorAll('.menuElementsAgregator>li').length
},
function(result) {
total_links = result.value;
console.log("Number of main links:" + total_links);
for (var i = 2; i <= total_links; i++) {
(function (i) {
browser.waitForElementPresent('.menuElementsAgregator', 3000)
.click('.menuElementsAgregator>li:nth-child(' + i + ')>a')
.waitForElementVisible('.menuElementsAgregator>li:nth-child(' + i + ')', 2000)
.execute(
function () {
return document.querySelectorAll('.menuElementsAgregator>li:nth-of-type(' + i + ')>.tsr-nav-second-level .has-sub .clickableTabWithLink').length
},
function(result) {
total_links2 = result.value;
console.log("Number of links:" + total_links2);
for (var j = 2; j <= total_links2 + 1; j++) {
browser.waitUntilElementIsClickable('.menuElementsAgregator>li:nth-child(' + i + ')')
.click('.menuElementsAgregator>li:nth-child(' + i + ')')
.waitForElementPresent('.menuElementsAgregator>li:nth-of-type(' + i + ')>.tsr-nav-second-level>li:nth-of-type(' + j + ').has-sub', 5000)
.click(' .menuElementsAgregator>li:nth-of-type(' + i + ')>.tsr-nav-second-level>li:nth-of-type(' + j + ').has-sub .clickableTabWithLink:first-child')
.pause(1000)
.waitForElementVisible('.games-list', 5000);
}
}
)
})(i);
}
})
The problem is that total_links is not an integer but an object.
Try to replace
console.log("Number of main links:"+ total_links);
with
console.log("Number of main links:", total_links);
That will show you what's inside total_links. If you can't fix it add a comment with the content of total_links
Absolutely this code would not work, because you cant use a callback in a loop like that,your index 'i' in second loop would be equal 'total_links.length' all the time. You can try this:
.execute(
function() {
return document.querySelectorAll('.menuElementsAgregator>li').length
},
function(result) {
total_links = result.value;
console.log("Number of main links:" + total_links);
for (var i = 2; i <= total_links; i++) {
(function(i){ // this is a closure
browser.waitForElementPresent('.menuElementsAgregator', 3000)
.click('.menuElementsAgregator>li:nth-child(' + i + ')>a')
.waitForElementVisible('.menuElementsAgregator>li:nth-child(' + i + ')', 2000)
.execute(
function() {
return document.querySelectorAll('.menuElementsAgregator>li:nth-child(' + i + ')>.tsr-nav-second-level>.has-sub').length
},
function(result2) {
total_links2 = result2.value;
console.log("Number of links:" + total_links2);
for (var j = 0; j <= total_links2; j++) {// i = total_link.length already, before get in to this loop.
browser.waitForElementPresent('.menuElementsAgregator>li:nth-child(' + i + ')>.tsr-nav-second-level>.has-sub:nth(' + j + ')', 3000)
.click('.menuElementsAgregator>li:nth-child(' + i + ')>.tsr-nav-second-level>.has-sub:nth(' + j + ')>a')
.pause(3000)
.waitForElementVisible('.games-list', 5000);
}
}
)
})(i) // close
}
}
)
You should take a look at api .perform() , this will be help a a lot for this kind of work. It made my code cleaner and readable.
Ps: Spend some time to research closure.

Get argument of executed function in function Javascript

I have a function that measures time execution of function, and cleans DOM after each execution:
function measureTimeExecution(domID, testFunc){
console.time("timer");
for(var i = 0; i < 10; i++){
testFunc();
var getDiv = document.getElementById(domID);
}
getDiv.empty();
console.timeEnd("timer");
}
Function that creates new ul
function createList_Task_2(divID){
var createNewUL = document.createElement("ul");
createNewUL.id = "phoneList";
document.getElementById(divID).appendChild(createNewUL);
for(var i = 0; i < phones.length;i++){
var chunk = "<li>" + phones[i].age +"<br>" + phones[i].id +"<br><img src='"
+ phones[i].imageUrl +"'/><br>" + phones[i].name + "<br>" + phones[i].snippet + "</li>";
document.getElementById("phoneList").innerHTML += chunk;
}
}
But iy gives me: Uncaught TypeError: testFunc is not a function;
Example:
measureTimeExecution("div1", createList_Task_3("div1"));
Is it possible to get somehow domID in measureTimeExecution as a argument of testFunc?
the problem is that when you are calling measureTimeExecution you are runing the parameter, instead pass a function again.
look at this code it should work
measureTimeExecution("div1", function () { createList_Task_3("div1"); });
function measureTimeExecution(domID, testFunc)
The function expects the second argument to be a function, but calling it like measureTimeExecution("div1", createList_Task_3("div1"));, it provides the return of createList_Task_3("div1"). Since createList_Task_3 returns nothing, the default return is undefined.
For it to be a function as well as be able to be provided the ID, it should return a function like this:
function createList_Task_2(divID){
return function(){
var createNewUL = document.createElement("ul");
createNewUL.id = "phoneList";
document.getElementById(divID).appendChild(createNewUL);
for(var i = 0; i < phones.length;i++){
var chunk = "<li>" + phones[i].age +"<br>" + phones[i].id +"<br><img src='"
+ phones[i].imageUrl +"'/><br>" + phones[i].name + "<br>" + phones[i].snippet + "</li>";
document.getElementById("phoneList").innerHTML += chunk;
}
}
}

How do I loop a variable in the Javascript function call?

I have the following loop for a series of similar click events in jQuery. Everything works fine except for the last line below with the comment. How can I make each loop iteration call these functions respectively: step1(), step2(), step3(), etc.?
for (i = 0; i < 7; i++) {
$("#stepbox" + i).click(function(){
$("#step" + i).show();
$("#stepswrapper section").not("#step" + i).hide();
$("#stepbox" + i).addClass("stepboxactive");
$("#stepboxmain div").not("#stepbox" + i).removeClass("stepboxactive");
step + i(); // I'm stuck here. This doesn't work to create the function calls step1(), step2(), etc.
});
}
Assuming your functions are defined in the global context:
for (i = 0; i < 7; i++) {
$("#stepbox" + i).click(function(){
$("#step" + i).show();
$("#stepswrapper section").not("#step" + i).hide();
$("#stepbox" + i).addClass("stepboxactive");
$("#stepboxmain div").not("#stepbox" + i).removeClass("stepboxactive");
window["step" + i]();
});
}
make an array of the step functions.
var step = [
function () { /* step 0 */ },
function () { /* step 1 */ },
function () { /* step 2 */ }
// ...
];
for (i = 0; i < 7; i++) {
$("#stepbox" + i).click(function(){
$("#step" + i).show();
$("#stepswrapper section").not("#step" + i).hide();
$("#stepbox" + i).addClass("stepboxactive");
$("#stepboxmain div").not("#stepbox" + i).removeClass("stepboxactive");
step[i]();
});
}

how to create two different nameSpaces in one same nameSpace avoiding covering the first one?

i want to use two string(which i dont know their content) to create two nameSpace.And i dont want to create a new one if the nameSpace exists.
here is my code:
function createNameSpace(nameSpace)
{
var spaceArr = nameSpace.split(".");
var curSpace = window;
//judge if this nameSpace exists.
var i;
for(i in spaceArr)
{
curSpace = curSpace[spaceArr[i]];
if(curSpace)
window.alert("nameSpace1:" + nameSpace + "\ncurSpace do exists:" + curSpace + "\ni:" + i + "\nspaceArr[i]:" + spaceArr[i] + "|");
else
{
curSpace = {};
window.alert("nameSpace1:" + nameSpace + "\ncurSpace not found:" + curSpace + "\ni:" + i + "\nspaceArr[i]:" + spaceArr[i] + "|");
break;
}
}
//now curSpace must have been created.
i++;
//window.alert("nameSpace2:" + nameSpace + "\ni:" + i + "\nspaceArr.length:" + spaceArr.length);
//create the nameSpace
for(;i < spaceArr.length; i++)
{
//window.alert("nameSpace2:" + nameSpace + "\ni:" + i + "\nspaceArr.length:" + spaceArr.length);
if(i == 0)
{
window[spaceArr[i]] = {};
curSpace = window[spaceArr[i]];
}
else
{
//window.alert("nameSpace3:" + nameSpace + "\ncurSpace[spaceArr[i]]:" + curSpace[spaceArr[i]]);
curSpace[spaceArr[i]] = {};
curSpace = curSpace[spaceArr[i]];
}
}
return curSpace;
}
the problem is,if i send"myTest.myNameSpace"and"myTest.monaNameSpace" into this func,it all alert"curSpace not found",which should be "curSpace do exists:" when i send "myTest.monaNameSpace" . i can`t tell where the mistakes are,can someone tell me?
I think your algorithm is a little to complex. I refactored it a little and added a test to it and verified it worked in the console. I have also written this code several times, so i am pretty sure i have hit your requirements
function createNameSpace(nameSpace)
{
var spaceArr = nameSpace.split(".");
var curSpace = window;
//judge if this nameSpace exists.
var i = 0;
for(i = 0;i < spaceArr.length; i++)
{
var next = spaceArr[i];
console.log(curSpace, next);
if(curSpace[next] == undefined)
{
curSpace[next] = {};
curSpace = curSpace[next]
}
else
{
curSpace = curSpace[next];
}
}
return curSpace;
}
createNameSpace("myTest.myNameSpace");
console.log(myTest.myNameSpace);
myTest.myNameSpace.myName = "Leat Hakkor";
createNameSpace("myTest.monaNameSpace");
console.log(myTest.monaNameSpace);
console.log(myTest.myNameSpace.myName);

Categories