1

I have a function updateChartData that uses a global variable array with information from a file server.

  async function updateChartData(){
    console.log("Updating chart with ID", 1);

    await buildChartData(1).then(
        console.log(workItems)
    )

In addition to a function buildChartData that refreshes the information in the array, this function has recursive behaviour.

async function buildChartData(currentID){  
    axios.get(`http://localhost:8888/_wit/workItems?id=${currentID}`).then(function(res){
        let currentItem = res.data.value[0]
        console.log(currentItem)
        //Find child items
        let childItemIds = []
        for (let link in currentItem.Links){
            let currentLink = currentItem.Links[link]
            childItemIds.push([currentLink.TargetWorkItemId])
            console.log("Found Child",currentLink.TargetWorkItemId)
        };

        workItems[currentItem.WorkItemId] = {
            'Title':currentItem.Title,
            'WorkItemType':currentItem.WorkItemType,
            'State':currentItem.State,
            'Links': childItemIds
        };

        //Recursion
        if (currentItem.Links.length >0){
            childItemIds.forEach(buildChartData)
        };
    });
  };

The issue I am having is that despite explicitly creating an async function and using the await keyword. The program proceeds to resolve the await and move in to the then function. This inconsistency means that inside of the updateChartData function I do not have access to the full chart data.

The purpose of the application is essentially to find all nodes and verticies within a tree structure for "work items", served up on a file server. So the number of recursions necessary for a given request is unknown so i cannot use that as a means to delay resolving a promise. When the function runs to completion that data is valid, but it is sequence of events I am having difficulty with.

I have tried returning a promise within the async function but it resolves after the first recursion occurs. Additionally, I have explored using the setTimeout function with no success either.

I am finding synchronous bahaviours in JavaScript very difficult with complex functions, any help would be appreciated.

Edit: Posting my working solution as it may be teachcable for other users. using the await keyword inside and outside of the recursive for loop async function buildChartData(currentID){ const res = await axios.get(http://localhost:8888/_wit/workItems?id=${currentID}`) let currentItem = res.data.value[0] console.log(currentItem) //Find child items let childItemIds = [] for (let link in currentItem.Links){ let currentLink = currentItem.Links[link] childItemIds.push([currentLink.TargetWorkItemId]) console.log("Found Child",currentLink.TargetWorkItemId) };

workItems[currentItem.WorkItemId] = {
    'Title':currentItem.Title,
    'WorkItemType':currentItem.WorkItemType,
    'State':currentItem.State,
    'Links': childItemIds
};

//Recursion
if (currentItem.Links.length >0){
  for await (const childId of childItemIds){
    await buildChartData(childId)
};
};

};`

Then in the updateChartData function (which acts as main) the following code:

  async function updateChartData(){
console.log("Updating chart with ID", state.trackedID);

await buildChartData(state.trackedID)
console.log(workItems)

These modifications make the program await all recursive actions and the workItems data is logged correctly.

MLancaster
  • 11
  • 2
  • Try to turn this code to code with `async/awaut` instead of `then` – Anatoly Mar 12 '23 at 18:10
  • "*despite explicitly creating an async function and using the await keyword.*" - you're not actually using the `await` keyword? You use `.then()` twice, and in `childItemIds.forEach(buildChartData)` you use neither. – Bergi Mar 12 '23 at 18:12
  • Also notice that your `buildChartData` function does not `return` anything – Bergi Mar 12 '23 at 18:13

1 Answers1

0

I think the issue here is that you are not actually awaiting the buildChartData function inside the forEach loop. Instead, you are passing it as a callback function without awaiting it...so the loop will continue executing without waiting for the buildChartData function to complete for each child item.

You can try Promise.all to wait for all the child buildChartData functions to complete before moving on to the next iteration of the loop. You can modify the buildChartData function to return a promise that resolves when all child buildChartData functions have completed.

async function buildChartData(currentID) {  
    const res = await axios.get(`http://localhost:8888/_wit/workItems?id=${currentID}`);
    const currentItem = res.data.value[0];
    console.log(currentItem);
    //Find child items
    const childItemIds = [];
    for (let link in currentItem.Links){
        let currentLink = currentItem.Links[link];
        childItemIds.push(currentLink.TargetWorkItemId);
        console.log("Found Child", currentLink.TargetWorkItemId);
    };
    workItems[currentItem.WorkItemId] = {
        'Title':currentItem.Title,
        'WorkItemType':currentItem.WorkItemType,
        'State':currentItem.State,
        'Links': childItemIds
    };
    //Recursion
    const promises = childItemIds.map(buildChartData);
    await Promise.all(promises);
};
DevKev
  • 5,714
  • 6
  • 24
  • 29
  • Hi, I tired implementing the code you suggested and it did not affect the execution order of the program. The debug log shows it does not await even the inital request in the buildChartData function. – MLancaster Mar 12 '23 at 19:15
  • After some modifications I have got this to work. Thank you very much for your patience and help with this! – MLancaster Mar 12 '23 at 19:26
  • Thanks, please post your solution and glad you got it working. @MLancaster – DevKev Mar 13 '23 at 14:56