0

I am trying to retrieve some data from neo4j for my web app. I have my code structured in the following manner:

When I click the button to retrieve the data, call

var childNodes = getAllChildNodes(uuid, ""); //uuid: node specific id in neo4j, second param not important

//do something with childNodes 

....

In getAllChildNodes(),

function getAllChildNodes(uuid, filter) {
    /*
    prepare json data to send
    */
    
    var resultNodes = {}
    var successFunction = function(data) {
        //store data in resultNodes ...
        //do something with the data ...
    }

    var failFunction = function(xhr, status, error) {
        //if query fails
    };

    //call to API function
    try {
        getChildrenAPI(jsonData, successFunction, failFunction)
    } catch (err) { console.log(err) }

    return resultNodes
}

In getChildrenAPI

function getChildrenAPI(jsonData, doneFunction, failFunction) {
                    var request = $.ajax({
                    method : 'POST',
                    url: myurl,
                    data : JSON.stringify(jsonData),
                    dataType : 'json',
                    contentType : 'application/json',
                    cache : false,
                    async : true,
                });
                request.done(function (data) {
                    doneFunction(data)
                })
                request.fail(function (xhr, status, error) {
                    failFunction( xhr, status, error );
                });
}

The problem is that my childNodes var does not get populated. When I inspected further, in my getAllChildNodes() function, resultNodes is returned before the query data is stored in successFunction(). I thought this would be an async issue, so I made sure to check that the AJAX call had its async property set to true, but that didn't solve it. So I tried using async await on my getAllChildNodes(), but that didn't work either. So my question is, what am I doing wrong here? I'm still new to the idea of async so this was the best I can do. If someone can please help me with this I would really appreciate it.

  • 1
    Does this answer your question? [How to return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – Lennholm Jul 18 '21 at 03:24

3 Answers3

1

It seems that you misunderstood the problem. AJAX requests are asynchronous by default. What you want, as far as I can tell by seeing your code is to be able to use the result of the request after the request in the code. For that you need to make it synchronous. You can specify async to be true, you can await and so on. However, it's a terrible idea in most cases to make your requests asynchronous. If you synchronize your request, then nothing else will run and your page will hang while you await.

What if a request lasts for 10 seconds? In that case your page is unresponsive for ten seconds if you synchronize the request.

What if you send 100 requests and on average they take 1 second? Then your page hangs for 100 seconds.

The best practice is to avoid syncrhonising your requests whenever possible and only do so when absolutely necessary. Instead, you will need to get used to callbacks, that is, functions defined to be executed once the request is completed and define the post-request behavior in them. You could also use promises or web workers, depending on your exact situation.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
0

async function getAllChildNodes(uuid, filter) {
    /*
    prepare json data to send
    */
    
    var resultNodes = {}
    var successFunction = function(data) {
        //store data in resultNodes ...
        //do something with the data ...
    }

    var failFunction = function(error) {
        //if query fails
    };

    //call to API function
    try {
      var data = await $.ajax({
          method : 'POST',
          url: myurl,
          data : JSON.stringify(jsonData),
          dataType : 'json',
          contentType : 'application/json',
          cache : false,
          async : true,
      });
      successFunction(data);
    } catch (err) { 
      console.log(err);
      failFunction(err);
    }

    return resultNodes
}

var childNodes = getAllChildNodes(uuid, "");
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous"></script>

Javascript is single-threaded & non-blocking language so it will not execute code asynchronously.
To make your code sync, you have to create an async function that manage the async code (ajax, timeout, read a file, ...)

-1

I think you're looking for something like the following:

getAllChildNodes(uuid, "", function done(results) {
  // Results populated by the done callback.
  console.log(results);
});

The trick here is that you need to be keeping track of how many requests were kicked off and when they finished.

So we can then change the definition of getAllChildNodes to call our doneCallback once all requests have been "processed".

function getAllChildNodes(uuid, filter, doneCallback) {
  // How many calls do we need to make.
  const callsToMake = [1,2,3];

  // Track when all calls were made by the results.
  const results = [];
  const ajaxDoneCallbackCheck = function () {
    if (results.length === items.length) {
      doneCallback(results);
    }
  };
  const ajaxSuccessCallback = function (data) {
    results.push(data);
    ajaxDoneCallbackCheck();
  };
  const ajaxFailCallback = function (error) {
    results.push(error);
    ajaxDoneCallbackCheck();
  }

  // Iterate through ajax calls to make.
  for (const callToMake of callsToMake) {
    // Do ajax stuff.
    console.log('Request data');
    getChildrenAPI(ajaxSuccessCallback, ajaxFailCallback);
  }
}

Now results needs to be processed in our original done callback like so:

getAllChildNodes(uuid, "", function done(results) {
  // Results populated by the done callback.
  console.log(results);

  // Iterate results.
  for (const result of results) {
    if (result instanceof Error) {
      console.error(result);
    } else {
      // Process or track result!
      console.log(result);
    }
  }
});
Nate-Wilkins
  • 5,364
  • 4
  • 46
  • 61