Bug Tracker

Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#12023 closed feature (wontfix)

Add new $.sjax method to explicitly support synchronous AJAX

Reported by: swaj Owned by:
Priority: high Milestone: 1.8
Component: ajax Version: 1.8b1
Keywords: Cc:
Blocked by: Blocking:

Description

Currently, the $.ajax method has an "async" option that has been marked as deprecated in jQuery 1.8 (see #11013). While using synchronous ajax is generally not the best idea, there are definitely some use cases where it is perfectly acceptable and valid (i.e. form validation on submit or the beforeunload event).

There has been some discussion about moving this functionality into a "compat" plugin, which could also cause some headaches because web developers would have to introduce another dependency just to restore functionality that is provided by the browser (and should ideally be wrapped by jQuery anyway).

While I understand that removing this "async" option from the $.ajax method will allow Promise implementation to proceed forward, I believe that the proper solution to this problem is to introduce a new method called $.sjax to provide synchronous AJAX capabilities. This would allow the work on Promises to proceed forward, and it would also allow developers to use synchronous AJAX when they truly need it. jQuery should provide this wrapper to ensure proper cross-browser functionality.

Change History (10)

comment:1 Changed 7 years ago by dmethvin

Milestone: None1.8
Status: newopen

Whether this is the final name or not, it seems reasonable to have a ticket for it. Let's see if we can at least get the api outlined before 1.8 release.

comment:2 Changed 7 years ago by dmethvin

Component: unfiledajax
Priority: undecidedhigh

comment:3 Changed 7 years ago by jaubourg

What do we expect to achieve with this? As has been outlined in all the sync/async discussion, the need for synchronous request is situational (mainly due to constraints like the unload event or some flash integration). Why would we put something like this in core? Why don't we leave that to a plugin if we ever remove synchronous requests (which seems highly unlikely given the uproar)?

comment:4 Changed 7 years ago by scottgonzalez

Because there are legit uses and it makes sense for us to support them. Synchronous ajax requests are not an edge case, they're fairly common. While many people do use them inappropriately, there are valid, common use cases, as has been mentioned over and over.

comment:5 Changed 7 years ago by swaj

It's also worth noting that XHR supports synchronous requests, so I think hiding/deprecating this in jQuery just doesn't make sense. Just because something has the potential to be abused doesn't mean it should be excluded. I think introducing a new method with documentation that appropriately explains the issues/pitfalls/etc. is much better than just removing it and not providing any alternative.

comment:6 Changed 7 years ago by dmethvin

Given that $.ajax is defined to return a jqXHR and we're now making that async, it seems like we need a different method. Or is there some solution via a plugin that will return $.ajax to sync behavior in Promises? That seems like it would be harder.

comment:7 Changed 7 years ago by jaubourg

I'm well aware of the use-cases. I never said they didn't exist. But they are very specific use cases when, for various reasons, an asynchronous request wouldn't have time to complete. The two that come to mind are doing ajax during the unload event and deal with nasty security issues in flash. As far as I'm aware of, other uses of synchronous requests can be replaced by asynchronous ones.

Anyway, what's important is that synchronous requests are unavoidable in certain situations.

Today, implementing sjax is quite simple (I assume a single options map):

$.sjax = function( options ) {
    return $.ajax( $.extend( options ||  {}, { async: false } ) );
};

That's because our promise implementation is synchronous.

Now, let's suppose we make our promise implementation truly asynchronous (the reason of the whole debacle in the first place). To implement $.sjax, we'd need:

  • to recode the whole logic around xhr implementations and their perks in all browsers (we could re-use the transport but it will require some refactoring),
  • to decide what can and cannot be requested synchronously (text, json, xml?),
  • to decide how to handle callbacks (no promise, so only a single success and error callback? Back to 1.4.x?), if it can be timed out, etc, etc, etc

This is actually a lot of code, most of which is a duplicate of what $.ajax does. The API will be confusing because it's just close enough to $.ajax to make sense while being different enough to warrant an entire documentation page.

I, for one, don't see the point. Let's abandon making our promise implementation asynchronous and we're good as is: we have support for synchronous requests with no need for code duplication or yet another API.

If some insist on making our promise implementation asynchronous (which will de-facto break synchronous requests), then let's leave sjax to be defined in a plugin, it's specific enough.

Whatever the decision, I don't see the point in having yet another helper in ajax, especially if it doesn't rely on $.ajax itself and brings inconsistencies in the API.

comment:8 Changed 7 years ago by dmethvin

It seems like $.sjax() is a new API so it doesn't have to do whatever $.ajax does today. It could return a raw XHR object and require the user to deal with it, no callbacks at all. It can take whatever subset of $.ajax options we want it to.

But yeah, this all started because we wanted a fully async Promise. If we give that hope up--FOREVER--we don't need to change $.ajax at all. This is the time to make that decision, though. I don't want to revisit it once 1.9+2.0 are released.

Unfortunately, it seems code like this is already out in the wild but I've talked to tbranyen and he understands it would need to be rewritten a bit if we made this change. There may be other uses of Deferred that are relying on the sync behavior as well.

comment:9 Changed 7 years ago by dmethvin

Resolution: wontfix
Status: openclosed

After discussing this with jaubourg it seemed pretty clear that a $.sjax would either duplicate a lot of $.ajax code or require a significant refactor. So instead, what I've proposed we guarantee for the future is that we simply guarantee that the complete/success/error callbacks work for async:false requests. We will not guarantee that the promise-based interface will stay synchronous.

comment:10 Changed 7 years ago by anonymous

Alternative found on another website :

function synchronous_ajax_call(url) {
            var AJAX;
            if (window.XMLHttpRequest) {
                AJAX = new XMLHttpRequest();
            } else {
                AJAX = new ActiveXObject("Microsoft.XMLHTTP");
            }
            if (AJAX) {
                AJAX.open("POST", url, false);
                AJAX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                AJAX.send();
                return AJAX.responseText;
            } else {
                return false;
            }
        }
Note: See TracTickets for help on using tickets.