Ajax is a technology that allows developers to make asynchronous HTTP requests to retrieve or send data from the server without the need for a full page refresh. Developers have been using jQuery for a long time to make this process less cumbersome than it would be in pure JavaScript.
In my previous article An Introduction to jQuery’s Shorthand Ajax Methods, I discussed some of the most commonly used Ajax calls in jQuery, including $.get(), $.post(), and $.load(), which are convenient methods for making Ajax requests in jQuery in a few lines of code.
But, sometimes we need more control over the Ajax calls we want to make. For example, we want to specify what should happen in case an Ajax request fails or we need to perform an Ajax call function but its result is only needed if retrieved within a certain amount of time. In such situations, we can rely on another function provided by Ajax in jQuery, called $.ajax(), which is the topic of this tutorial.
Key Takeaways
- Versatility and Control: The jQuery $.ajax() function offers a flexible and powerful way to make asynchronous HTTP requests, allowing developers extensive control over the request and response process. It supports a wide array of settings, such as specifying callback functions for success and error, setting request headers, handling data types, and adding authentication tokens for HTTP access authentication requests, which makes it highly adaptable to various scenarios beyond the capabilities of shorthand Ajax call functions like $.get(), $.post(), and $.load().
- Comprehensive Configuration Options: The article highlights the comprehensive list of configuration options available with $.ajax(), which can cater to nearly any requirement one might have while making Ajax calls. From modifying request headers to processing response data, and from handling errors to setting up cross-domain requests, $.ajax() provides developers with the tools necessary to fine-tune their Ajax requests and responses to fit their application’s needs precisely.
- Relevance in Modern Development: Despite the advent of newer APIs like Fetch, the jQuery $.ajax() function remains a relevant and valuable tool in web development, especially for maintaining legacy codebases or for developers who prefer the simplicity and consistency offered by jQuery. Its ease of use, combined with the depth of functionality, ensures that $.ajax() can still play a crucial role in projects that require Ajax calls, highlighting jQuery’s ongoing utility in the web development ecosystem.
- Advanced Error Handling and Retry Strategies: Robust error handling is demonstrated using retry mechanisms with exponential backoff, ensuring applications can gracefully recover from temporary network or server failures. Developers can also define global error handlers to debug and track errors across multiple requests.
The $.ajax() Function
The jQuery $.ajax() function is used to perform an asynchronous HTTP request. It was added to the library a long time ago, existing since version 1.0. The $.ajax() function is what $.get(), $.post(), and $.load() calls behind the scenes using a preset configuration. The signatures of this function are shown below:
$.ajax(url[, settings])
$.ajax([settings])
The URL in Ajax parameter is a string containing the Ajax URL you want to reach with the jQuery Ajax call, while settings is an object literal containing the configuration for the Ajax request.
In its first form, this function performs an Ajax request using the URL parameter and the options specified in the settings. In the second form, the URL is specified in the settings parameter or can be omitted, in which case the request is made to the current page.
The list of the options accepted by this function, described in the next section, is very long, so I’ll keep their description short. If you want to study their meaning in depth, you can refer to the official documentation for $.ajax().
The Settings Parameter
There are a lot of different options you can specify to bend $.ajax() to your needs. In the table below, you can find their names and their description sorted in alphabetic order:
Parameter | Default Value | Possible Values | Description and Use Case |
accepts | { “*”: “*/*” } | Any MIME type string | The content type sent in the request header that tells the server what kind of response it will accept in return. |
beforeSend | None | Function | A pre-request callback function that can be used to modify the jqXHR object before it is sent. |
cache | true (except for script) | true or false | Set this option to false to force requested pages not to be cached by the browser. |
complete | None | Function | A function to be called when the request finishes (after success and error callbacks are executed). |
contentType | “application/x-www-form-urlencoded; charset=UTF-8” | MIME type string | The content type of the data sent to the server. |
context | window | Any object | An object to use as the context (this) of all Ajax-related callbacks. |
converters | Depends on dataType | Object mapping | An object containing dataType-to-dataType converters |
crossDomain | false | true or false | Set this property to true to force a cross-domain request on the same domain. |
data | None | Object, String, or Array | The data to send to the server when performing the Ajax request. |
dataFilter | None | Function | A function to be used to handle the raw response data of XMLHttpRequest |
dataType | text | xml, html, json, text, etc. | The type of data expected back from the server. Avoid using jsonp requests, as it is largely obsolete. |
error | None | Function | A function to be called if the request fails. |
global | true | true or false | Whether to trigger global Ajax event handlers for this request. |
headers | None | Object | An object of additional headers to send to the server. |
ifModified | false | true or false | Processes the response only if it has changed since the last request. |
isLocal | Depends on environment | true or false | Forces jQuery to treat the current environment as local. |
mimeType | None | MIME type string | A string that specifies the mime type to override the XHR mime type. |
password | None | String | A password to be used with XMLHttpRequest in response to an HTTP access authentication request. |
processData | true | true or false | Determines whether data should be automatically serialized to a query string. |
scriptCharset | None | String | Sets the charset attribute on the script tag used in the request but only applies when the “script” transport is used. |
statusCode | None | Object | Maps HTTP status codes to callback functions. |
success | None | Function | A function to be called if the request succeeds. |
timeout | 0 (no timeout) | Integer | A number that specifies a timeout (in milliseconds) for the request. |
type | “GET” | “GET”, “POST”, etc. | The type of request to make. |
url | Current page URL | String | A string containing the URL to which the request is sent. |
username | None | String | A username to be used with XMLHttpRequest in response to an HTTP access authentication request. |
xhr | None | Function | A callback function for creating the XMLHttpRequest object. |
xhrFields | None | Object | An object to set on the native XHR object. |
That’s a pretty long list, isn’t it? Well, as a developer, you probably stopped reading this list at the fifth or sixth element, I guess, but that’s fine. The next section will be more exciting because we’ll put the $.ajax() function and some of these options into action.
Putting It All Together
In this section, we’ll discuss $.ajax() function in detail and some of its options in action.
A First Example of $.ajax()
We’ll start with a simple demo that reproduces the same code we developed in the previous article. As a recap, we will imagine that we have an element in our website having an ID of main that represents the main content. What we want to do is asynchronously load data from the main content of the pages referenced by the links in the main menu, which ideally has main menu as its ID. We want to retrieve only the content inside this element because the other parts of the layout don’t change, so they don’t need to be loaded.
This approach is intended as an enhancement because if the user visiting the website has JavaScript disabled, they will have the fallback of still being able to browse the website using the usual synchronous mechanism. In this example, we’re assuming that all the links in the menu are internal links.
We’ll start with a simple demo that reproduces the same code we developed in the previous article, but this time we’ll adopt $.ajax(). The code we developed previously is shown below for your convenience:
$('#main-menu a').on('click', function(event) {
event.preventDefault();
$('#main').load(this.href + ' #main *', function(responseText, status) {
if (status === 'success') {
$('#notification-bar').text('The page has been successfully loaded');
} else {
$('#notification-bar').text('An error occurred');
}
});
});
Updating this snippet to employ the $.ajax() function, we obtain the code shown below:
$('#main-menu a').on('click', function(event) {
event.preventDefault();
$.ajax(this.href, {
success: function(data) {
$('#main').html($(data).find('#main *'));
$('#notification-bar').text('The page has been successfully loaded');
},
error: function() {
$('#notification-bar').text('An error occurred');
}
});
});
Here you can see that I used the first form of the function. I’ve specified the URL to send the request to as the first parameter and then a settings object as the second parameter. The latter takes advantage of just two of the several properties discussed in the previous section — success and error — to specify what to do in case of request succeeds or a request fails respectively.
Adding Custom Headers and Handling HTTP Access Authentication Requests
Image Source: https://developer.okta.com/blog/2019/02/14/modern-token-authentication-in-node-with-express
In this second example, we’ll explore how to enhance your AJAX requests by adding custom headers, handling authentication tokens, and interacting with APIs that require specific security measures. These are common scenarios when working with modern web applications that communicate with external APIs.
Let’s say you are interacting with an API that requires a token for an HTTP access authentication request. You can include this token as part of the request headers using the headers option in $.ajax():
$('#main-menu a').on('click', function(event) {
event.preventDefault();
$.ajax({
url: this.href,
headers: {
"Authorization": "Bearer YOUR_TOKEN_HERE",
"X-Custom-Header": "CustomValue"
},
success: function(data) {
$('#main').html($(data).find('#main *'));
$('#notification-bar').text('The page has been successfully loaded with custom headers');
},
error: function() {
$('#notification-bar').text('An error occurred while loading the page with custom headers');
}
});
});
In this example, the Authorization header includes a bearer token, which is commonly used to authenticate the request with an API securely. Additionally, the X-Custom-Header serves as an extra metadata header, often required by proprietary APIs to provide additional context or comply with specific server requirements.
Adding custom headers is particularly useful when working with secure APIs, ensuring proper authentication and providing the server with any necessary contextual information.
Managing Complex Data Structures with $.ajax()
APIs often require structured data, such as nested JSON objects, to handle filters or hierarchical information. The following example demonstrates how to send structured data using the data property of $.ajax() function:
$.ajax({
url: '/api/products',
headers: {
"Authorization": "Bearer YOUR_TOKEN_HERE",
"X-Custom-Header": "CustomValue"
},
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
category: 'electronics',
filters: {
brand: 'Samsung',
priceRange: [100, 500]
}
}),
success: function(data) {
$('#main').html($(data).find('#main *'));
$('#notification-bar').text('Thed ata has been sent successfully');
},
error: function() {
$('#notification-bar').text('An error occurred while sending data');
}
});
Here, the contentType: ‘application/json’ specifies the data format being sent, and JSON.stringify() converts JavaScript objects into JSON strings for compatibility with APIs. This is ideal for APIs requiring complex queries or hierarchical filters.
Real-World Application Scenario: Live Search Feature
Now that you understand how $.ajax() works, let’s take a look at a real-life scenario in which $.ajax() is incredibly useful. For example, imagine you’re building an online store, and you want users to search for products dynamically as they type in a search box. Instead of reloading the entire page every time, the search results should appear instantly, giving users a smooth and interactive experience.
How It Works
When a user types in the search box, their query string is sent to the server via an AJAX request. The server processes the query string and returns matching products, which are displayed immediately on the page. This keeps the experience fast and seamless.
Here’s how you can handle it:
$('#search-box').on('input', function() {
let query = $(this).val().trim();
if (query.length > 2) {
$.ajax({
url: "/search-products",
type: "GET",
data: { query: query },
success: function(response) {
let results = response.products.map(product => `
<div class="product">
<h3>${product.name}</h3>
<p>${product.description}</p>
<span>Price: $${product.price}</span>
</div>
`).join('');
$('#search-results').html(results);
},
error: function() {
$('#search-results').html('<p>Unable to load results. Please try again.</p>');
}
});
} else {
$('#search-results').empty();
}
});
Why This Matters
Think about how much time users save when they don’t have to reload the page to see search results. This approach:
- Enhances Usability: Results appear in real-time, making the interface feel more responsive.
- Saves Bandwidth: Only the required data is fetched, reducing unnecessary load on the server.
- Improves User Experience: A faster, smoother interaction keeps users engaged.
By applying this simple pattern, you can transform a basic search box into a dynamic, user-friendly feature that elevates your web application.
Best Practices for Secure and Reliable AJAX Requests
To ensure your AJAX requests are secure and reliable, it’s important to follow best practices that address common security concerns and optimize the development process.
Error Handling Strategies
- Implement robust error handling using an error callback function or global handlers to provide meaningful feedback to users and handle retries gracefully.
- Avoid infinite retries to prevent server overload; instead, implement strategies like exponential backoff.
Cross-Domain Requests and Security Considerations
Image Source: https://medium.com/swlh/how-cors-cross-origin-resource-sharing-works-79f959a84f0e
- Use Cross-Origin Resource Sharing (CORS) to handle cross-domain requests securely. Ensure the server explicitly allows requests from trusted origins.
- Prevent Cross-Site Scripting (XSS) attacks by escaping or sanitizing inputs and outputs. Use tools like DOMPurify to sanitize user inputs before processing them.
- Validate all user inputs on both the client and server sides to ensure that only expected data is processed.
- Always transmit sensitive data over HTTPS to secure data in transit and prevent eavesdropping or man-in-the-middle attacks.
Improve AJAX Security
- Use libraries like DOMPurify to sanitize user inputs and prevent XSS attacks.
let cleanInput = DOMPurify.sanitize(userInput);
- Use HTTP headers like Content-Security-Policy (CSP) to mitigate injection attacks.
- Implement anti-CSRF tokens to prevent Cross-Site Request Forgery attacks.
$.ajax({ url: '/secure-endpoint', type: 'POST', headers: { 'X-CSRF-Token': csrfToken }, data: { input: cleanInput } });
- Avoid exposing sensitive API keys in the front-end by storing them securely on the server side.
- Regularly audit and update your dependencies, including jQuery, to address known vulnerabilities.
Debugging Ajax Requests: What To Do When a Request Fails
Debugging Ajax jQuery requests can sometimes be tricky due to their asynchronous nature and the involvement of both client-side and server-side code. Here are some effective tips for debugging issues related to the jQuery $.ajax() method:
1. Use Browser Developer Tools
- Network Tab: Check the Network tab in your browser’s developer tools to inspect the Ajax request. Verify the request URL, headers, payload, and response. Look for any errors or unexpected status codes.
- Console Tab: Look for JavaScript errors or warnings in the Console tab that might indicate problems with your jQuery Ajax call or its callback functions.
2. Check the Server-Side Logs
- If the jQuery Ajax call reaches the server but doesn’t behave as expected, check the server-side logs for errors or warnings. This can provide clues about issues in the server-side code or configuration.
3. Log Request and Response
- Temporarily add console.log() statements in the success, error, and complete callbacks of the $.ajax() call to log the response or any error messages. This can help you understand what the server is returning or why the request might be failing.
4. Verify the Data Type
- Ensure that the dataType option in your $.ajax() call matches the actual type of data returned by the server. Mismatches here can cause jQuery to incorrectly process the response, leading to unexpected behavior.
5. Test API Endpoints Separately
- Use tools like Postman or curl to manually test the API endpoint. This can help you verify that the API is working correctly and understand the expected request format and response data.
6. Validate JSON Responses
- For JSON data, validate the response using an online JSON validator or debugging tools to ensure it is well-formed. Malformed JSON can cause parsing errors.
7. Use jQuery.ajaxError() for Global Error Handling
- Bind an event handler to ajaxError on the document to catch and handle Ajax request errors globally. This can help you identify and debug Ajax requests that fail across your application.
$(document).ajaxError(function(event, jqxhr, settings, thrownError) {
console.error("AJAX Request Failed: ", settings.url, thrownError);
});
8. Simplify and Isolate
- Simplify your $.ajax() call or isolate it in a simple environment/page to verify its behavior without interference from other scripts or Ajax calls.
Sometimes, these errors can be temporary due to network issues. Implementing retries with increasing delays (exponential backoff) can automatically handle such situations and improve the reliability of your application.
function ajaxWithRetry(url, retries, delay) {
$.ajax({
url: url,
success: function(data) {
console.log('Success:', data);
},
error: function() {
if (retries > 0) {
setTimeout(() => {
ajaxWithRetry(url, retries - 1, delay * 2);
}, delay);
} else {
console.error('Failed after retries');
}
}
});
}
ajaxWithRetry('/fetch-data', 3, 1000);
The function retries the request up to 3 times, doubling the delay after each failure. This helps to handle network glitches or temporary server unavailability.
Optimizing the Performance of Ajax Requests
Optimizing the performance of Ajax requests is crucial for creating fast and responsive web applications. When using the jQuery $.ajax() function, consider the following tips to enhance performance:
1. Use GET for Retrieving Data
- HTTP GET requests are generally faster and can be cached by the browser. Use HTTP GET to retrieve data whenever possible and reserve HTTP POST requests for actions that change the server’s state.
2. Limit Data Transfer
- Minimize Payload Size: Send and receive only the data that is necessary. Large payloads can significantly slow down your application.
- Compress Data: Use compression techniques for both request and raw response data if your server and clients support it.
3. Cache Responses
- Browser Caching: Use HTTP headers such as Cache-Control and ETag to enable the browser to cache frequently requested resources.
Cache-Control: max-age=3600
- Application-Level Caching: Cache data locally using tools like localStorage, sessionStorage, IndexedDB, or popular libraries such as Dexie.js, and PouchDB for frequently accessed resources.
let cachedData = localStorage.getItem("products"); if (cachedData) { renderProducts(JSON.parse(cachedData)); // Use cached data } else { $.ajax({ url: "/api/products", type: "GET", success: function(data) { localStorage.setItem("products", JSON.stringify(data)); // Cache data renderProducts(data); } }); }
- Server-Side Caching: Tools like Redis or Memcached can cache data on the server, reducing database queries for frequently requested data.
4. Asynchronous Requests
- Make sure your requests are asynchronous (async: true, which is the default) to prevent blocking the main thread. This keeps your application responsive while the data is being fetched.
5. Batch Requests
- Reduce HTTP Requests: Combine multiple requests into a single one if you’re fetching data from the same endpoint, reducing the overhead of multiple HTTP connections.
6. Use Promise Chains for Multiple Requests
- If you have dependent requests, use jQuery’s promise and .then() chaining to handle them in a clean and efficient way, reducing callback nesting and improving readability.
7. Error Handling
- Implement robust error handling to deal with failed requests. Avoid unnecessary retries for requests that are likely to fail repeatedly.
8. Timeout Configuration
- Set a reasonable timeout for your AJAX requests (timeout setting). This prevents requests from hanging indefinitely and degrading the user experience.
9. Avoid Unnecessary Ajax Calls
- Before making a request, check if the data is already available on the client side or if the operation is really necessary.
10. Optimize Server-Side Processing
- Ensure that the server-side processing of Ajax requests is optimized. Faster server responses lead to better performance.
11. Minimize DOM Manipulations
- When updating the DOM based on Ajax responses, minimize the number of manipulations and reflows. Use document fragments or batch updates to the DOM.
Alternatives to jQuery’s $.ajax()
With modern JavaScript, there are numerous options for making HTTP requests, each catering to different needs. While $.ajax() has been a reliable choice for years, newer alternatives like Fetch API have gained popularity for modern development. Let’s compare these options.
When To Use $.ajax()
- Ideal for legacy projects already using jQuery.
- Convenient for quick integration in environments where jQuery is already loaded.
- Provides built-in support for complex configurations and callbacks.
When To Use Fetch or Other Alternatives
- Recommended for modern applications or frameworks like React, Vue, or Angular.
- Offers cleaner syntax with Promises and async/await.
- More lightweight, with no dependency on external libraries.
- Supported natively in JavaScript and modern browsers.
Other alternatives to $.ajax() include popular tools like Axios, SuperAgent, and Node-Fetch, each catering to specific needs in modern development.
Version Compatibility and Deprecation Notices
As jQuery has evolved, some features and practices in the $.ajax() API have been deprecated or replaced with modern alternatives. Staying aware of these changes ensures compatibility and maintainability in your projects.
- Synchronous Requests (async: false)The use of synchronous requests is deprecated due to their impact on user experience. Always use asynchronous requests (async: true), which is the default.
- JSONP Request SupportJSONP requests were once used for cross-domain requests and are now largely obsolete. Use modern methods like CORS for secure cross-domain communication.
- Deprecated OptionsMethods like jqXHR.error() and jqXHR.success() are replaced by done() and fail() for promise-based handling:
$.ajax("/api/data") .done(response => console.log("Success:", response)) .fail(error => console.error("Error:", error));
- Shift Toward Modern AlternativesNative tools like the Fetch API or libraries like Axios are often preferred in modern projects due to their simplicity and compatibility with async/await.
Conclusion
In this tutorial, I discussed the most powerful of the Ajax functions offered by jQuery, $.ajax(). It allows you to perform Ajax requests with a lot of control over how the request is sent to the server and how the response is processed. Thanks to this function, you have the tools you need to satisfy all of your project’s requirements in case none of the shorthand functions is a good fit.
To have an even better understanding of the potential of this function, I encourage you to play with the corresponding code samples and to try to modify the code to use some other options accepted by the settings parameter.
If you want to learn more about JavaScript, check out our JavaScript titles at SitePoint Premium. Have fun!
FAQs About jQuery’s Ajax Function
What Is jQuery’s Ajax Function?
jQuery Ajax function is a powerful and flexible method that allows you to make asynchronous HTTP requests from a web page to a server and handle the response without having to reload the entire page. It supports advanced configurations like custom headers, authentication tokens, and file uploads.
How Do I Use jQuery’s Ajax Function?
To use the jQuery Ajax function, you need to call $.ajax() and provide it with a configuration object that specifies various settings like the URL, HTTP method, data to send, and callbacks to handle the response. You can also define security headers and handle errors gracefully with retry mechanisms if needed.
How Does an Ajax Call jQuery Work?
An Ajax call jQuery is performed using the $.ajax() method. This method allows developers to make asynchronous HTTP requests to retrieve or send data to a server without refreshing the page.
What Are the Basic Parameters of the $.ajax() Function?
The basic parameters of the $.ajax() function include:
- url: The target URL for the request.
- method: HTTP POST request or GET request.
- data: The data to be sent with the request, either as JSON, query strings, or form data.
- success: A callback function to handle a successful response.
- error: A callback function to manage errors.
What Is the Purpose of the Success Callback in $.ajax()?
The success callback is executed when the Ajax request succeeds. It receives the raw response data returned from the server as its parameter, allowing you to process and manipulate the data as needed. For example, dynamic search results can be updated instantly using this callback.
Can I Handle Errors in jQuery Ajax Requests?
Yes, you can. The error callback function in the Ajax request jQuery configuration lets you define a function to handle errors that occur during the Ajax request. This can be useful for scenarios like network errors or server-side issues.
How Can I Send Data Along with My Ajax Request?
You can use the data parameter in the $.ajax() configuration to send data to the server. This data can be in various formats like a query string, a JSON object, or serialized form data.
Is the jQuery Ajax Function the Only Way to Make Ajax Requests?
No. Modern alternatives, like the Fetch API, Axios, SuperAgent, and Node-Fetch, provide simpler syntax and better support for Promises and async/await. The article includes a detailed comparison to help you choose the right tool for your project based on its requirements.
Is jQuery Required for Using Ajax in Web Development?
No. Modern browsers natively support the Fetch API, which can replace jQuery’s Ajax function for most use cases. However, jQuery’s Ajax function is still useful in legacy projects or scenarios where jQuery is already integrated.
Is jQuery’s Ajax Function Still Relevant Today?
Yes, but its relevance depends on the project. For legacy systems or projects already using jQuery, $.ajax() remains a practical choice. For newer applications, alternatives like Fetch API, Axios, or SuperAgent are often preferred due to their Promise-based syntax and integration with modern frameworks like React and Vue.