2

I am trying to create a function that produces AJAX calls and returns the response.

function msg(message) { send = new XMLHttpRequest(); send.open("POST", "msghandler.php", false); send.setRequestHeader("Content-type","application/x-www-form-urlencoded"); send.send("msg="+encodeURI(message)); return send.responseText; } 

As you can see, right now I am using a synchronized call, but this isn't an optimal solution because it is very common in my debugging for something to go wrong on the server side and end up freezing my browser. Is there a way to make the call asynchronous and have the response be returned by the function?

7
  • 2
    This is pretty simple in jquery if you're looking to use a framework. Commented Aug 21, 2012 at 20:50
  • I'm trying to make my project as lightweight as possible, so I'm attempting to avoid using frameworks. Commented Aug 21, 2012 at 20:51
  • 1
    @JakeM: can you elaborate? The same problem with freezing will occur in jQuery and jQuery doesn't have any solution to it. Commented Aug 21, 2012 at 20:52
  • @Madbreaks Yes, I've spent about two hours doing the like in addition to trying stuff such as JavaScript timeouts and creating some while loops that basically simulated it being synchronous and didn't really help. Commented Aug 21, 2012 at 20:53
  • 1
    @JakeM: of course jQuery can do AJAX and AJAX calls are asynchronous by default (not only in jQuery). But OP wants "the response be returned by the function", which he can't do without blocking, with or w/o jQuery. Commented Aug 21, 2012 at 21:02

3 Answers 3

3

You can’t return something that doesn’t exist. But you can return a promise object if you are afraid of indenting callbacks in eternity. Here is a very simple example:

function msg(message) { var done = function(){}; send = new XMLHttpRequest(); send.open("POST", "msghandler.php", true); send.setRequestHeader("Content-type","application/x-www-form-urlencoded"); send.send("msg="+encodeURI(message)); send.onreadystatechange = function() { if(send.readyState == 4){ done(send.responseText); } }); return { ready: function(fn) { done = fn; } }; }; msg('foo').ready(function(response) { alert(response); }); 

Many frameworks already implemented deferred objects.

Sign up to request clarification or add additional context in comments.

3 Comments

That looks like a good solution... think I'll probably go with this or callbacks.
+1 for "You can’t return something that doesn’t exist" and for promise object idiom.
If you're afraid of indenting callbacks, just name them
2

Go completely asynchronous and pass in a callback as a parameter to the function. That's the proper way to use JavaScript. Do something like so:

function msg(message, callback) { var xmlhttp; if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest(); } else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { // asynchronously call the callback with the result callback(xmlhttp.responseText); } } xmlhttp.open("POST", "msghandler.php", true); xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xmlhttp.send("msg="+encodeURI(message)); } 

1 Comment

I was guessing that would be the only option. Inconvenient, but I should be able to work with it. I'll probably create separate functions that do synchronous calls as well.
2

It's not possible because JavaScript engines in browsers (web workers aside) are inherently single-threaded. If you want your msg() function to return the response from the server, call to that function will take at least as much time as the HTTP request needs. Furthermore, because JavaScript engine is single-threaded, no other code can run by that time. So the browser must freeze during synchronous HTTP calls.

You cannot work around it and no library can help, that's the way the cookie crumbles. You either have a blocking call or you use callbacks (which I guess you can do).

See also

7 Comments

I'm curious, how is jQuery able to accomplish it?
@flep from jQuery docs "Note that synchronous requests may temporarily lock the browser"
Isn't it the browser's implementation of JavaScript and the XMLHttpRequest object that is responsible for making the call synchronous or asynchronous? Otherwise, you wouldn't need the code if(XMLHttpRequest){...}else { create MS ActiveX Object }. I'm curious as to how AJAX calls are becoming synchronous. Isn't the A in Ajax for "Asynchronous"?
@villecoder I don't think that has to do with it being synchronous, when you open the request you decide. I believe by default it is asynchronous, but setting async to false makes it synchronous.
@villecoder: AJAX is asynchronous by default, if it was synchronous, your browser would freeze every other second. The browser is free to use internal background thread or non-blocking socket I/O, JavaScript developer doesn't care.
|