Jump to content

Javascript callback voodoo


LostKobrakai
 Share

Recommended Posts

Can somebody help me out with some Javascript, which I can't get my head around. I know the theory about closure and callbacks, but how the heck can I have something that reports back after multiple callbacks are all finished. Now I know again why I dislike node so much.

I'm trying to build a local html-only page, that uses openstreetmaps so to add latitude and longitude to a csv table based on the city. Getting it to call the rest api of osm is easy, but I can't figure out, how to spit out the new csv after all those calls are done. 

function getGeoCodes(jsonFromCsv){
  for (var i = json.length - 1; i >= 0; i--) {
    //AJAX requests and adding the lat / lon to the json object
  }

  // After everything is done
  reformatToCsv(json);
}

Edit: Also I'd like this calls to be parallel and not one after another.

Link to comment
Share on other sites

Feel like you left out the most interesting parts there :P

It sounds like you’re not using jQuery, but if you did, Ajax requests would return Deferred objects that expose done events. You could then use $.when to bind these Deferreds together into a single Deferred that fires such an event once for the entire queue, once all “inner” Deferreds have finished. I recently had to wrap my head around this. Voodoo is an apt description.

I think in vanilla JS (I hope this is not the name of some JS library :D) you would create an XMLHttpRequest object for each request, whose onreadystatechange events you handle in one function. There you could naively count the successes in a global variable and do your thing once you have all of them.

So it kinda depends on what the requests look like and what events you can subscribe to.

The requests should run in parallel if you simply send() them one after the other, i. e. the program will not wait for the server response until it executes the next request.

  • Like 1
Link to comment
Share on other sites

Taking what you have:

function getGeoCodes(jsonFromCsv, callback){ // <- I added the callback parameter WITHOUT parentheses
  for (var i = json.length - 1; i >= 0; i--) {
    //AJAX requests and adding the lat / lon to the json object
  }

  // After everything is done
  callback(json); // <- and call it inside the function, just as you had it
}

// when calling getGeoCodes, you will have to pass the function as a parameter
getGeoCodes(yourJson, reformatToCsv) // <- here is where we pass the function, also WITHOUT parentheses 

PS: I'm not sure what is jsonFromCsv in your case, but here I'm assuming it's some other parameter that you will need and it's not related to the callback function.

PS2: I renamed the function inside the other function to "callback" to make it clear that you don't need to use the name of the function there, only while calling it outside.

PS3: The reason that I insist so much on having the function without parentheses on the parameters is because the parentheses will cause the function to be called immediately. We want to pass it only as a reference, so we can call it only later inside the function.

PS4: by the way @Jan, I didn't comment on your avatar before, but next time make sure you add a custom avatar before it's too late ;)

  • Like 3
Link to comment
Share on other sites

That’s how callbacks work, but I believe LostKobrakai can’t use a standard callback, because his requests will be asynchronous. So the callback would get executed as soon as all requests have been made, but it won’t wait for the actual responses. For that he’ll have to use events. So either pool the events of the request objects and fire your own event when all are done, or have a single function handling all requests and executing the callback upon completion.

@diogo hehe, I’m glad you got that reference %)

@Mike Anthony that’s brilliant! I’ll have to save that link :lol:

Link to comment
Share on other sites

There you could naively count the successes in a global variable and do your thing once you have all of them.

That was exactly the right hint.

Feel like you left out the most interesting parts there :P

I don't think so. In my eyes these big callback wars are a wast of time and asyncron code would deserve a easier way to manage stuff. Instead of pasing data though a shitload of callbacks, it would be so nice to be able to just return stuff after it's done. In a way, that the callback just "resumes" where it left.

Link to comment
Share on other sites

Ya, sorry, I should have read the question better :)

Based on Jan's idea, I think a good approach would be to, for each request callback, add 1 to that global variable on success, and check if the variable is already the total of the requests. If so, fire the function right there.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...