0

Trouble finding the reason why JavaScript for loop is not executing. Wrote 2 simple functions below that I want to execute and run i.e.: Bought method should try to "simulate" synchronous code. The problem is that for some reason the for loop in the addNodes() method is never executed. However, if I run this separately i.e. for example line by line

var result = [];
var addressBookNodes = await generateAddressBooksNodes();
addNodes(result, addressBookNodes);

that tells me that the code is running fine however most likely it has something to do with the asynchronous nature of the generateAddressBooksNodes method. If I simply run the command :

var addressBookNodes = await generateAddressBooksNodes();

in the browser, I get an array of objects exactly what I was expecting to get. Basically the generateAddressBooksNodes returns a promise and when that promise is resolved I can see the correct array returned however what I do not understand why the for loop is not executed if the nodes objects have at least one element as shown in the picture below.

function addNodes(result, nodes){
    console.log("3");
    console.log(nodes);
    for (var num in nodes) {
        console.log("4");   
        let singleNode = nodes[num];
        console.log(singleNode);        
        console.log("5");
        result.push(singleNode);
    }
}

async function getAddressBookAndContactNodes() {  
    var result = [];
    console.log("1");
    var addressBookNodesPromise = generateAddressBooksNodes();
    addressBookNodesPromise.then( (arrayOfAddressBookNodes) => {
        console.log("2");
        addNodes(result, arrayOfAddressBookNodes);          
    })      
    return result;  
}

here is the picture of what that looks in the browser

Update 26 August 2020 :

After poking around the "arrayOfAddressBookNodes" object i noticed something really strange. I added additional print statement and printed the length of the "arrayOfAddressBookNodes" array. The length of the array is 0 when runned in the function. I do not understand how the length can be 0 if the object is printed shortly before the for loop and as shown on the picture below the length there is :1. What the hell is going on here?

I found another article i.e. JavaScript Array.length returning 0 that is basically explaining this. And in one of the commends it has been mentioned to use Map instead of an Array. I decided to use Set, and still get the same error i.e. the size of the set is 0 although the Set contains an object. i.e. below is the code and the picture of that execution.

  async function getAddressBookAndContactNodes() {
    var result = new Set();
    console.log("1");
    var addressBookNodes = await generateAddressBooksNodes();
    console.log("2");
    console.log(addressBookNodes);
    console.log("3");
    console.log("addressBookNodes size : " + addressBookNodes.size);
    addressBookNodes.forEach(function(value) {
        result.add(value);
    });
    console.log("6");
    console.log(result);
    console.log("7");
    return result;
}

example using set

all this is really confusing to someone having a c++ backgroud, it makes my head explode.

Update 2 : 26 August 2020. Ok i solved my problem. The problem was that the the promises are not working withing the for loop everything is explained here.

i need to use the regular "for (index = 0; index < contactsArray.length; ++index) " instead of foreach. after that it all worked. Somehow this leaves the impression that the tools of the language are broken in so many ways.

donkey
  • 1
  • 1
  • 3
    You are returning the `result` before the promise `then()` populates the array – charlietfl Aug 25 '20 at 16:11
  • @charlietfl can you give me a hint what would be a common solution to that i.e. i have learned that i can not return from the promise, and thus i am not sure what to do here – donkey Aug 25 '20 at 16:13
  • To be honest I don't really see why you need to push all those into a different array and don't just return `addressBookNodesPromise ` and use the array it resolves with – charlietfl Aug 25 '20 at 16:16
  • well i have multiple arrays i.e. one for address books , one for contacts , mailing lists and i need to combine all the objects from those array into a single one in this case it is called "result". I have just tried to show a simplified version of the code which is not working. – donkey Aug 25 '20 at 16:20
  • 1
    OK, makes sense... BTW a simpler way to add them without needing a loop is `result.push(...nodes)` Also should not use `for in` on arrays – charlietfl Aug 25 '20 at 16:25
  • @charlietfl, my problem here is that the console.log("4"); and console.log("5"); is not displyed at all. But thanks for the hint on reuslt.push. However the question is why is console.log("4"); not displayed at all? – donkey Aug 25 '20 at 16:29
  • `for...in` is for iterating over object properties. For arrays, use `for...of`. – connexo Aug 25 '20 at 19:44
  • I may be missing something but `async function getAddressBookAndContactNodes() { return Promise.all([generateAddressBooksNodes(), generateContacts()]) .then([addressBookNodes, contacts] => { // here do whatever is necessary to combine the two arrays. // return combined Array. }); }` seems to be a more sensible approach. – Roamer-1888 Aug 26 '20 at 00:04
  • Javascript has array-like objects that are not Arrays. To cast an array-like object as Array, use [Array.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from). – Roamer-1888 Aug 26 '20 at 07:47
  • Why are you not using your working first snippet (the one with the `await`) in `getAddressBookAndContactNodes`, instead of the broken `then` callback?! – Bergi Aug 26 '20 at 07:51
  • @Bergi at the end of the day it does not matter if i am using async await or .then, since they are bought the same async await is just sugar. What do you mean with broken then callback. If it is broken can you please let me know what exactly is wrong. – donkey Aug 26 '20 at 13:21
  • @donkey As charlieftl explained, you are returning the `result` array before the `then` callback did run. This kind of mistake cannot happen with `await`. – Bergi Aug 26 '20 at 14:19

1 Answers1

1

If generateAddressBooksNodes is returning a promise, you can use async to wait for the results:

async function getAddressBookAndContactNodes() {

    var result = [];
    console.log("1");
    var addressBookNodesPromise = await generateAddressBooksNodes();
    // note await here. Also, unless you're using this at a later time in your code, you can save space by not assigning it to a variable and simply returning generateAddressBooksNodes
    
    addNodes(result, arrayOfAddressBookNodes);
    return result;
}
Atlante Avila
  • 1,340
  • 2
  • 16
  • 37
  • I do not understand why this should solve the problem, although i must say await seems much cleaner and i will definitely use it. the parts 4 and 5 do not run. Are you sure that is the problem – donkey Aug 25 '20 at 16:25
  • just tried this , this is not solving the original problem where the for loop is not beeing runned – donkey Aug 25 '20 at 16:27