Skip to main content

Bug Tracker

Side navigation

#11013 closed enhancement (fixed)

Opened December 13, 2011 04:48PM UTC

Closed June 04, 2012 05:23PM UTC

Last modified October 28, 2013 06:45AM UTC

Deprecate use of Deferred/Promise with sync $.ajax

Reported by: jaubourg Owned by:
Priority: low Milestone: 1.8
Component: ajax Version: 1.7.1
Keywords: Cc:
Blocked by: Blocking:
Description

The async option will allow, if set to false, to make synchronous ajax requests.

It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous).

Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350

However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.

Attachments (0)
Change History (45)

Changed December 13, 2011 04:50PM UTC by jaubourg comment:1

component: unfiledajax
description: The async option will allow, if set to false, to make synchronous ajax requests. \ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous (because we cannot assume ajax is always asynchronous). \ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350 \ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.The async option will allow, if set to false, to make synchronous ajax requests. \ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous). \ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350 \ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.
keywords: → 1.8-discuss
milestone: None1.8
priority: undecidedlow

Changed December 13, 2011 04:50PM UTC by jaubourg comment:2

summary: Remove async options from $.ajaxRemove async option from $.ajax

Changed December 13, 2011 04:51PM UTC by jaubourg comment:3

blocking: → 10467

Changed December 13, 2011 04:57PM UTC by jaubourg comment:4

description: The async option will allow, if set to false, to make synchronous ajax requests. \ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous). \ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350 \ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.The async option will allow, if set to false, to make synchronous ajax requests.\ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous).\ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350\ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.

+1

Changed December 13, 2011 05:57PM UTC by dmethvin comment:5

description: The async option will allow, if set to false, to make synchronous ajax requests.\ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous).\ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350\ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.The async option will allow, if set to false, to make synchronous ajax requests. \ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous). \ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350 \ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.

+1, Deprecate yes, remove no (at least not any time soon). People might think twice about using a deprecated feature which is our goal here.

Changed December 13, 2011 06:12PM UTC by jaubourg comment:6

Replying to [comment:5 dmethvin]:

+1, Deprecate yes, remove no (at least not any time soon). People might think twice about using a deprecated feature which is our goal here.

No, the goal would be to remove the option so that we are sure to only have asynchronous ajax requests. Deprecating sadly won't solve any problem.

Changed December 14, 2011 03:35AM UTC by dmethvin comment:7

status: newopen

Changed December 14, 2011 04:18PM UTC by timmywil comment:8

description: The async option will allow, if set to false, to make synchronous ajax requests. \ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous). \ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350 \ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.The async option will allow, if set to false, to make synchronous ajax requests.\ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous).\ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350\ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.

-1, I agree it's bad, but unfortunately used far too often

Changed December 19, 2011 05:37PM UTC by rwaldron comment:9

description: The async option will allow, if set to false, to make synchronous ajax requests.\ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous).\ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350\ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.The async option will allow, if set to false, to make synchronous ajax requests. \ \ It is the worst possible way to make ajax requests (it hangs the javascript VM), it also makes it impossible to implement Deferreds in a truly asynchronous fashion (because we cannot assume ajax is always asynchronous). \ \ Sadly, this synchronous possibility is used internally in jQuery in order to execute script tags with src attributes in html fragments: https://github.com/jquery/jquery/blob/master/src/manipulation.js#L350 \ \ However this will not work for cross-domain, so I think we could very well "remove" this feature and document everything properly.

-1

Changed January 18, 2012 03:49AM UTC by dmethvin comment:10

keywords: 1.8-discuss

This was voted neutral but in any case we cannot remove async without first deprecating it for a major version cycle. I'll leave this open.

Changed April 03, 2012 11:12PM UTC by scottgonzalez comment:11

How many bytes are we gaining by adding an option for deferreds to allow sync resolution as I suggested in #10467? I can't imagine it would be too much. If deferreds defaults to forced async resolution, and sync XHR was the only time we set the flag, then the deprecation could go in and we'd have an easy upgrade path for removing sync XHR if we ever got to that point.

Changed April 30, 2012 02:40PM UTC by JiDW comment:12

-1. Sometimes, a synchronous XHR request is exactly what you want to do (ie block the VM)

Changed May 16, 2012 04:53PM UTC by anonymous comment:13

Synchronous ajax requests are also the *only* type allowed (currently) in Webkit browsers after a form submission has taken place.

It's extremely useful to be able to perform an ajax request after a form submission, whether to update some data on the screen, or to implement a progress/polling tracker for a large form upload that contains uploaded files.

If this option is removed I don't know if there is a suitable workaround...

https://bugs.webkit.org/show_bug.cgi?id=23933

Changed May 16, 2012 05:00PM UTC by scottgonzalez comment:14

To complete anonymous' comment, sync XHR is also required for communication in beforeunload.

Changed June 04, 2012 05:23PM UTC by dmethvin comment:15

resolution: → fixed
status: openclosed
summary: Remove async option from $.ajaxDeprecate/remove async option from $.ajax

Marked for deprecation in 1.8, a new ticket will be created when it is removed.

Changed June 22, 2012 08:25PM UTC by akmurray@gmail.com comment:16

There is no technical reason to deprecate or remove this feature. Most people would agree that async=true is the way to go most of the time, but is isn't a functionally invalid option.

This feature is not similar to "browser sniffing the user agent" so don't treat it that way.

Changed June 22, 2012 09:06PM UTC by ajm comment:17

It's also the best possible way to make synchronous requests, which is necessary from time to time as the commenters above point out.

This seems like you're removing utility from $.ajax - utility that's part of the XHR spec - and feels an awful lot like a regression.

Are we really going to need to duckpunch synchronous XHR into jQuery > 1.9?

Changed June 22, 2012 09:32PM UTC by anonymous comment:18

Bad idea that asumes a lot about how other people are implementing ajax. I don't disagree that it's bad to load stuff synchronously, and I do believe that jQuery itself should stop using it INTERNALLY, but I don't advise limiting users of having such option.

Some legacy code that is written the old fashion way still works and transition may not be so straight forward, if you just remove it, it will cause too many problems to handle at once.

Changed June 22, 2012 09:43PM UTC by dmethvin comment:19

We can still support async via a compat plugin if needed, but leaving it in blocks several other important features like consistently async resolution of Deferreds.

Legacy code can either choose to include the compat plugin or continue to use an older version of jQuery--including 1.8, which has only deprecated the behavior but still allows it.

Changed June 23, 2012 03:50PM UTC by Gregory Jacobs <greg@greg-jacobs.com> comment:20

This is an awful, awful idea. As other users have mentioned, there is *no way* to guarantee that an ajax request completes in a beforeunload event handler without a synchronous request. And a backward compatibility plugin for this? Come on...

On our site, we use a beforeunload handler to persist any modified data to the server should the user navigate away from the page without saving their data. Yes, we have an auto-save, but it only runs after a timeout of inactivity (i.e. we don't want to run a save request for each character that the user types in...). The only way to get this request to execute when the user navigates away from the page is with a synchronous request.

So while it is true that in the general case, one doesn't want to use a synchronous request, we still need the ability to do so when needed (e.g. this situation). Therefore, to remove something like this from a generalized library is not only shortsighted, but terrible library design. If you want to discourage newbies from using synchronous requests, then discourage it in the docs. Don't simply remove a feature which is necessary.

And to include a backward compatibility plugin just for this feature? We use the CDN url to promote caching of the library between multiple websites. We don't want to include ''yet another'' request in the page for a backward compatibility plugin to provide a *necessary feature* which gives our users the best experience.

Changed June 23, 2012 04:01PM UTC by dmethvin comment:21

For the beforeonload case it seems like this should do. If so, it doesn't seem like too much of a burden.

function savePreciousData(url, data){
  var xhr = new XMLHttpRequest();
  xhr.open("POST", url, false);                             
  xhr.send(JSON.stringify(data));
}                           

Changed June 23, 2012 05:58PM UTC by Gregory Jacobs <gjslick@yahoo.com> comment:22

Replying to [comment:21 dmethvin]:

For the beforeonload case it seems like this should do. If so, it doesn't seem like too much of a burden.
> function savePreciousData(url, data){
>   var xhr = new XMLHttpRequest();
>   xhr.open("POST", url, false);                             
>   xhr.send(JSON.stringify(data));
> }                           
> 

So you're saying that we should request a change in the vendor library that we use (Backbone.js) which relies on jQuery for its ajax functionality, which currently accepts a config option of async: true/false, to instead build out the complete set of raw XMLHttpRequest code into the library just for the synchronous case?

Not to mention other libraries out there that support this?

...

Changed June 24, 2012 10:35AM UTC by kristo@waher.net comment:23

It is wrong to deprecate valid functionality of a browser. It's just insane how many occasions there are where this is useful, especially on requests where it is needed to pause the script while request happens.

Do not deprecate this. Period.

Changed June 25, 2012 02:06AM UTC by dmethvin comment:24

summary: Deprecate/remove async option from $.ajaxDeprecate async option from $.ajax

Clarifying the title to reflect the action taken in 1.8.

Changed June 25, 2012 06:50PM UTC by anonymous comment:25

If this is deprecated & eventually removed, you oblige yourselves to provide documentation for resolving the problems it will create. For instance, form validation that occurs during the submit event through AJAX (the ubiquitous Validation plugin offers this) often creates a race condition that only a synchronous request can resolve (AJAX request against a database, return, valid/invalid, continue). Not to mention the other examples provided in previous comments.

As stated above, removing valid behavior & forcing dependent libraries to re-implement it from the ground up is a poor decision.

Changed June 25, 2012 11:08PM UTC by anonymous comment:26

There are numerous valid use cases for synchronous Ajax. Discouraging it is good, but removing it is a bad idea.

An other not yet mentioned use case is when you need to do an a an Ajax request before a window.open (e.g. because the URL depends on data returned by the request) : doing the request asynchronously would cause the call to be blocked by the popup blocker since the stack trace does not originate from a user generated event anymore.

Changed June 26, 2012 03:12PM UTC by anonymous comment:27

-1 - I am also in the boat as a lot of the voices on here, removing this option will have negative ramifications on my site. I am very disappointed in seeing this.

Changed June 26, 2012 03:26PM UTC by anonymous comment:28

I agree with the others who have commented here. Asynchronous Ajax requests are the preferred method of communication, but there are times where we need to perform a synchronous request so that we can poll the server or save sensitive data before allowing the user to make any more changes to the page. Deprecate this if you must, as that may discourage those new to jQuery from using it all the time, but you cannot remove core functionality from your library like this. The change from .attr to .prop was already a pain to deal with, and you eventually backed down and supported backwards compatibility. It is very short-sighted to think that the backlash to this will not be just as large.

Changed June 26, 2012 04:11PM UTC by dmethvin comment:29

Sorry about the lack of clarity. The ticket is saying that $.ajax({ ... async: false ... }) is being deprecated, and that option will eventually be removed.

**It does not say there are no valid use cases for sync ajax. It does not say you are all bad people for doing sync ajax.It does not say there will be no way to do sync ajax--only that it won't be via $.ajax.**

As the ticket explains, the problem is that async: true is so different that it prevents the rest of the $.ajax plumbing and dependencies from being fixed. For example, we cannot consistently call Promise callbacks asynchronously if $.ajax supports Promises with async: false.

We *would* like to collect some real-world uses of sync ajax. Please post some links to your code, so we can understand the use cases we need to address. My working assumption is that sync ajax requests are very simple and don't require things like prefilters or non-XHR transports (duh!).

For example, there is one case in the Backbone.js code, and I've already talked with tbranyen about it. But the usage there is trivial and would be easy to fix in several ways since it isn't using much of $.ajax at all. Imagine a hypothetical $.sjax({ url: "/", success: function(){ ... }) instead for example.

Changed June 29, 2012 12:52PM UTC by Joe T. comment:30

Here's my real-world workflow where only a sync Ajax worked for me. Not saying it can't be rearranged to allow an async. (For the record, i did read the original ticket closely enough to know you're not wagging a finger at sync Ajax calls...) ;)

My application lets a user enter a customer name, and when they select the customer, info is pulled in from a 3rd party database, populating a form. The purpose is this data is submitted & pushed to a different system, but allows my user to edit data if necessary & add a couple required values the original data doesn't track.

The user isn't allowed to edit certain values (financial info), so if the source is invalid, they have to go back & fix it there. To deter edit attempts, the inputs are set to read-only. Once the user has filled in the additional info, they submit. The form is validated using Validation, with one field that MUST be verified against a different database. If it's invalid, the submit should fail & force the user to fix the value in the original source.

Since the value is validating in the submit event via Ajax, i can't use async because the submit action will proceed before a response is received. My sync request checks the value and sets an event-level (set within the event handler, but outside the Ajax call) boolean. That and the rest of the form validation determine whether the submit event continues.

As i've typed this up, i can think of a couple other places where i will try to fix this race condition, but it's an example of where sync requests would be legit & necessary barring alternate solutions.

Changed June 29, 2012 02:01PM UTC by dmethvin comment:31

Let me make clear what we are asking for. We do not need scenarios. We need the actual call to $.ajax you make. When possible provide links to code on Github, as with this link.

Changed June 30, 2012 02:51PM UTC by James Greene <james.m.greene@gmail.com> comment:32

A huge -1.

I enjoy Promises, though I tend to prefer the q implementation much more than jQuery's. However, I am shocked that producing Promises is taking priority over providing a cross-browser implementation of synchronous "AJAX" ("SJAX") requests, which is a very core concept to the web and sometimes a necessity -- I know we have one or two SJAX calls in our very expensive proprietary product today that cannot be removed. While Dave gives a 3-line alternative, I am disappointed as you jQuery devs more than most others know that the provided code is NOT correct for oldIE.

I would much prefer this be split into a separate "sjax" method [as Dave alluded to] in jQuery core (well, ajax) that DOES address cross-browser compatibility (at least through jQuery 1.9) than to force jQuery consumers to roll their own cross-browser "sjax" jQuery plugin or have to add another script request to pull such a plugin in.

One of the main uses in our product of an SJAX call is when a tiny Flash object is used to inject into the user's clipboard. Because this is only allowed by Flash security when a user interaction triggers it (e.g. mouse click on Flash object), the call to the server to dynamically fetch data that it invokes MUST return synchronously to still be within the requirements of the Flash security context necessary to allow clipboard injection.

Changed June 30, 2012 03:07PM UTC by James Greene <james.m.greene@gmail.com> comment:33

Sorry, to clarify the workflow there:

1. The Flash object invokes a JS function via ExternalInterface (not dissimilar from an SJAX interaction itself)

2. The JS function does some work/calculation, makes an SJAX call to the server

3. The server does some additional work, returns JSON response to the JS function

4. JS function returns the JSON back to the Flash caller

5. Flash parses the JSON object and injects it into the various sectors of the user's clipboard (plain text, RTF, HTML).

Changed July 02, 2012 07:07PM UTC by anonymous comment:34

I'd also like to say that we use synchronous Ajax requests in development to resources that are packaged in production (the most common case are external view files). Using synchronous requests prevents users from having to make callback functions constantly.

Changed July 05, 2012 02:42PM UTC by halcyon1234 comment:35

-1.

I use async:false for on-the-fly form validation. Specifically, the user enters their postal code. I need to do a complex db-look up to see if that is a supported postal code before they fill out any more of the form. There is a .Net CustomValidator, which calls a server-side PageMethod with

$.ajax{async:false, onSuccess:function(r){args.IsValid = r.IsValid}}

A .Net CustomValidator expects args.IsValid to be set before it exits its validation function. If I did async:true, the function would exit before onSuccess, and the validator would not work.

Changed July 13, 2012 06:57PM UTC by gfbj@excite.com comment:36

One instance of $.ajax async false: I have an application that depends on blur() to $.ajax to check whether a user name is available. Doesn't make sense to tell the user anything until the server replies.

I have other instances of async=false in other applications of projects I am no longer assigned to. If you want, I could go find them.

Changed July 13, 2012 06:59PM UTC by dmethvin comment:37

@gfbj, that would be good. We would like to see the actual code, not a description of the application of the code.

Changed July 13, 2012 07:24PM UTC by scottgonzalez comment:38

@gfbj You should really use async in that case anyway.

Changed July 14, 2012 02:39AM UTC by dmethvin comment:39

summary: Deprecate async option from $.ajaxDeprecate use of Deferred/Promise with sync $.ajax

NOTE THE CHANGED SUBJECT

The use of the Deferred/Promise functionality in synchronous ajax requests has been deprecated in 1.8. The $.ajax method with async: false is supported but you **must** use a callback parameter rather than a Promise method such as .then or .done.

So, for example this is supported for sync ajax:

$.ajax({
   ... async: false ...
   success: fn1,
   error: fn2
});

This is deprecated for sync ajax:

$.ajax({
   ... async: false ...
}).then(fn1, fn2);

Changed August 30, 2012 07:07AM UTC by anonymous comment:40

How would you go about opening a popup on the condition of a server check? For instance, if the server needs to connect to a 3rd party account using OAUTH but the access tokens are not yet in the system, or are no longer valid? The flow would be as follows:

Click an element in the page -> request the server to interact with the 3rd party -> tokens are missing or invalid -> server responds with authentication url -> browser opens the url in a popup to avoid interrupting the regular work flow, the user authenticates in the popup... later steps omitted.

As far as I know this flow is not possible with an asynchronous call to the server, since most browsers will catch the popup in the popup blocker. However, if the call is synchronous, the whole flow is within the click event handling and the popup WILL be allowed...

How would one go about implementing a flow like this with an asynchronous server call?

Changed August 30, 2012 12:50PM UTC by dmethvin comment:41

You implement it with sync ajax. Did you read the ticket? Sync ajax isn't going away in 1.9.

Further off-topic comments will just be removed to prevent other off-topic posts from following.

Changed August 30, 2012 03:04PM UTC by anonymous comment:42

Thanks, @dmethvin. This approach is a win-win, I think!

Changed October 28, 2013 03:24AM UTC by anonymous comment:43

I would recommend updating the documentation to clarify what is/is not deprecated or more importantly, showing a clear example of how to do an async request, as previously you could get responseText simply $.ajax().responseText which does not require any of the xhr callbacks. There are alot of no longer working async:false examples out there in the upper ranks of google, and it'd save people alot of time if the defacto documentation had a specific async:false example. I came across a situation where I absolutely needed the ajax call to block until completed, had a great deal of difficulty getting it to work(as many examples online use $.ajax()responseText), and along the way was wondering if I was mireading the note in the documentation. Had me wondering if perhaps async:false itself was deprecated and perhaps it was just poorly worded documentation. Using the success:function(){} callbacks for a synchronous method seems counter intuitive and I would have never guessed that would be the solution. For those who haven't been intemately familiar with jquery through it's api evolution, that message about xhr callbacks versus "success/error/complete callback" is kind of mysterious, and I didn't really understand it until I finally found a working example and am looking at it again.

Would strongly recommend adding an example to this page(add whatever "Will cause browser to freeze/is generally bad practice" disclaimer you want):

http://api.jquery.com/jQuery.ajax/

Maybe anchor link to the example, from the current note about deprecated async:false/xhr callbacks.

Changed October 28, 2013 03:25AM UTC by anonymous comment:44

Sorry should have read "to do an async:false request"

Changed October 28, 2013 06:45AM UTC by jaubourg comment:45

I'm surprised, $.ajax( { async: false } ).responseText should work, if not, this is a bug.