As you learned in the last article, AJAX is a collection of technologies. In this article, we’ll go one step further and explain in detail how to use Ajax techniques to retrieve data in a project. And in order to explain that, we need to first understand where we’re getting the data, and then we need to focus on how we’re getting the data.

1. Access to data

We know that AJAX is used to get data in a project in a way that prevents page refreshes, so where does the data come from? How do we know how to get this data? The answer is that we often use apis to interact with a wide variety of databases.

“API” stands for “Application Programming Interface.” You can imagine that some data is open and waiting to be used, and the way we get that data is by using the API. An API usually takes the form of a URL and provides a specified parameter name and value to help you locate the data you want to fetch.

Remember we mentioned that AJAX requires setup on the server side? We’ll come back to that later.


Second, the core of AJAX technology – XMLHttpRequest object

Let’s leave the server-side setup aside and focus on the core of AJAX technology: the XMLHttpRequest object.

The XMLHttpRequest object is an API provided by the browser to smoothly send requests to the server and parse the server response, without the browser page being refreshed. It will be the focus of the rest of this article, so let’s start at a higher level and get a global overview of the object:

  1. XMLHttpRequestIt’s just a JavaScript object, or rather a JavaScript objectThe constructor. In other words, it’s not mysterious at all, it’s special only in that it’s provided by the client (i.e. the browser) (not JavaScript native), and other than that, it has properties, methods, and needs to be passednewKeywords to instantiate, we just need to master them;
  2. XMLHttpRequestObjects are constantly being extended. As XML objects became widely accepted, the W3C began to develop standards to regulate their behavior. At present,XMLHttpRequestThere are two levels: Level 1 provides implementation details of XML objects, and Level 2 takes XML objects further, adding additional methods, attributes, and data types. However, not all browsers implement XML object level 2 content (no surprise, right?). ;

Let’s start by dissecting the attributes and methods of an XMLHttpRequest instance by creating an instance of an XML object:

const xhr = new XMLHttpRequest()
Copy the code

Properties of this instance, methods are:

methods

  • .open(): Ready to start an AJAX request;
  • .setRequestHeader(): Sets the request header information.
  • .send(): Send AJAX requests;
  • .getResponseHeader(): Get the response header information;
  • .getAllResponseHeader(): Gets a long string containing all the header information;
  • .abort(): Cancels asynchronous requests.

attribute

  • .responseText: contains the response body return text;
  • .responseXML: If the content type of the responsetext/xmlorapplication/xml, this property will hold the XML DOM document containing the corresponding data;
  • .status: HTTP status of the response;
  • .statusText: description of HTTP status;
  • .readyState: represents the current active phase of the Request/Response process

In addition, the browser provides the object with an onReadyStatechange listening event that is triggered whenever the readyState property of the XML instance changes.

Now that we’ve covered all the attributes of the XMLHttpRequest instance object, we’ll take a closer look at how these methods and attributes can be used to complete the flow of sending AJAX requests.


Prepare AJAX requests

To interact with the server, we first need to answer the following questions:

  • Do we want to capture data or do we want to store data? — Represented by differences in the way requests are made:GETorPOST;
  • Where is the request made? — the corresponding API address;
  • How to wait for the response? — There are two options for “synchronous” and “asynchronous”; (Network transport is a process, and the request and response do not happen simultaneously.)

The.open() method of the XMLHttpRequest instance is designed to answer all three of these questions. The.open() method takes three parameters: the request type, the request URL, and a Boolean value for whether it is an asynchronous request.

Here is an example of a.open() method call:

// This code initiates a GET synchronization request for "example.php". xhr.open("get", "example.php", false)Copy the code

The.open() method does an equally good job of preparing the AJAX request before you start cooking.

Now, let’s dig into some of the preparatory details:

(1) GET request and POST request

  • A GET request

GET requests are used to fetch data. Sometimes the data we need to fetch needs to be located by “query parameters”. In this case, we append the query parameters to the end of the URL for the server to parse.

The query parameter refers to a query parameter specified by? The string containing the corresponding key-value pair, separated by an ampersand, starting with a. Used to tell the browser which particular resource to query for.

const query = "example.php? name=tom&age=24" // "? Name = TOM&age =24" is a query parameterCopy the code

Note that the name and value of each parameter in the query string must be encoded using encodeURIComponent() (this is because some characters in the URL are ambiguous, such as “&”).

  • A POST request

POST requests are used to send data to the server that should be saved, so naturally a POST request requires one more piece of data to be saved than a GET request. So where does this data go? After all, none of the three arguments received by our.open() method are in the right place.

The answer is that the data that needs to be sent is eventually sent to the server as an argument to the.send() method, which can be of any size and type.

Here are two points to note:

  1. .send()Method parameters are not null, that is, GET requests that do not send any data need to be called.send()Method is passed to itnullValue;
  2. So far, we’ve seen two ways to send data to the server: a form submission and a POST request. Note that the server doesn’t treat the two equally, which means that the server needs to have code to handle the raw data that the POST request sends.

Fortunately, we can simulate form submission with a POST request in two simple steps:

  1. Set the request header parameters:Content-Type: application/x-www-form-urlencoded(The type of content when the form is submitted);
  2. Serialize the form data as a query string and pass it in.send()Methods;

Request URL address

Note here that with relative paths, the request URL is relative to the current page of executing code.

(3) Synchronous and asynchronous requests

AJAX is often thought of as asynchronous, but it’s not. AJAX is a technique for avoiding a page refresh after data is fetched, and it’s up to the developer to configure whether to wait for a server response synchronously or asynchronously based on business requirements (although it’s usually asynchronous).

You may be wondering, when do we need to use synchronous AJAX? In my own experience, it seems difficult to find the corresponding scenario. There’s a similar question on Stack Overflow, if you’re interested.

Finally, let’s briefly explain the difference between “synchronous” wait responses and “asynchronous” wait responses: “Synchronous” means that once the request is issued, any subsequent JavaScript code will not be executed, and “asynchronous” means that when the request is issued, subsequent JavaScript code will continue to execute and the corresponding callback function will be called when the request is successful.


Set the request header

Each HTTP request and response comes with a header containing information about the data, the sender’s network environment and state. The.setrequestheader () method provided by the XMLHttpRequest object gives the developer a way to manipulate both headers and allows the developer to customize the header of the request header.

By default, when an AJAX request is sent, the following header information is attached:

  • Accept: Types of content that the browser can handle;
  • Accept-Charset: character set that the browser can display;
  • Accept-Encoding: compression encoding that the browser can handle;
  • Accept-Language: The language the browser is currently set to;
  • Connection: Type of connection between browser and server;
  • Cookie: Any cookies set on the current page;
  • Host: domain of the page making the request;
  • Referer: the page URI from which the request was made;
  • User-Agent: user agent string for the browser;

Note that some browsers do not allow the.setrequestheader () method to override the default request header, so it is safer to customize the request header:

Xhr.setrequestheader ("myHeader", "MyValue")Copy the code

Send a request

At this point, we’re all set to send the request: the.open() method determines how to request, how to wait for the response and the request address, and even customizes the response header with.setrequestheader (). Now comes the most exciting moment: Use the.send() method to send AJAX requests!

// Send an AJAX request! const xhr = new XMLHttpRequest() xhr.open("get", "example.php", false) xhr.setRequestHeader("myHeader", "goodHeader") xhr.send(null)Copy the code

Well, it’s embarrassingly simple, isn’t it? Try another POST request:

// Send an AJAX request! const xhr = new XMLHttpRequest() xhr.open("post", "example.php", false) xhr.setRequestHeader("myHeader", "bestHeader") xhr.send(some_data)Copy the code

The forehead.. Always feel or almost what? Relax buddy, because we just made the request, we haven’t processed the response yet, so we’re going to take a look at it.


6. Processing response

Let’s look directly at how to handle a synchronous GET request response:

const xhr = new XMLHttpRequest() xhr.open("get", "example.php", false) xhr.setRequestHeader("myHeader", "GoodHeader ") xhr.send(null) So only when the server response will continue to execute the following code / / XHR. Therefore the status value must be as the default value if ((XHR) status > = 200 && XHR. Status < 300) | | XHR. Status = = 304) { alert(xhr.responseText) } else { alert("Request was unsuccessful: " + xhr.status) }Copy the code

The above code is not hard to understand. We use the previously mentioned xhr.status property (which, in case you forgot, stores the HTTP status of the response) to determine whether the request was successful, and if so, we read the return value stored in the xhr.responseText property. However, when our request is asynchronous, the problem becomes slightly more complicated. Since it is an asynchronous request, the JavaScript engine will execute the following statement after the xhr.send(NULL) statement is executed, and we are bound to get a default xhr.status value because there is no time to respond. Therefore, we will never be able to get the requested resource.

How to solve this problem? The answer is by adding an onReadyStatechange event handler to the XMLHTTPRequest instance (of course you can use the dom2-level specification’s.addeventListener () method directly, but note that IE8 does not support this method).

The XHR instance’s readyStatechange event listens for changes in the xhr.readyState property, which you can think of as a counter that accumulates as the AJAX process progresses, with the following values:

  • 0: uninitialized — not yet called.open()Methods;
  • 1: Start — already called.open()Method, but not yet called.send()Methods;
  • 2: send — already called.send()Method, but no response has been received;
  • 3: Receive: some response data has been received.
  • 4: Completed — all response data has been received and is ready for use on the client.

With this time handler listening on the AJAX process, the rest is much simpler: an asynchronous GET request looks like this:

const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
    if (xhr.readystate == 4) {
        if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
            alert(xhr.responseText)
        } else {
            alert("Request was unsuccessful: " + xhr.status)
        }
    }
}
xhr.open("get", "example.php", true)
xhr.send(null)
Copy the code

Note: To ensure cross-browser compatibility, you must specify an event handler before calling the.open() method, which makes sense when you think about it. After all, the execution of the.open() method is also covered by the event handler’s listening scope, right?


7. Cancel asynchronous requests

Sometimes, you may need to abort an asynchronous request before the response is received. At this point, you call the.abort() method.

This method causes the XHR object instance to stop firing events and no longer allows access to any object properties associated with the response. Without the monitors, we can’t judge the response anymore, can we?

Note, however, that when the AJAX request is terminated, you need to manually unbind the XHR object instance to free up memory space.


🎉🎉 Congratulations! Now that you’ve learned all the basics of AJAX, you know what AJAX is, what it means to exist, and how to actually make an AJAX request and receive the response, you’re an AJAX guru! Congratulations to you! That’s great! 🎉 🎉















🤜 great, respected AJAX master, you have not even left, then I will teach you the last part of AJAX secrets, to help you become a real AJAX ninja, this is your persistence earned!

XMLHttpRequest Level 2

Remember we mentioned at the beginning that the W3C came up with the XMLHttpRequest Level 2 specification? While not all browsers implement the specification, some are implemented by all or most browsers. Want to be an AJAX ninja? Read on.

Hint: In this section, you’ll see a lot of text about browser compatibility. I hope you don’t get bored. After all, this is ninja practice, right?

(1) FormData type

FormData is a new data type (constructor) that XMLHttpRequest Level 2 provides for us. Remember how we disguised a POST request as a form submission? FormData makes this process much easier because the XHR object recognizes that the incoming data type is an instance of FormData and automatically configures the appropriate header information.

FormData can be used as follows:

Let data1 = new FormData() data1.append("name", "Tom") xhr.send(data1) let data2 = new FormData(document.forms[0]) xhr.send(data2)Copy the code

Another benefit of FormData is that it allows you to upload binary data (images, video, audio, etc.) over traditional AJAX requests. See this link for details.

FormData browser compatibility:

  • The desktop
    • Internet Explorer 10+ is supported by other browsers
  • The mobile terminal
    • Android, Firefox Mobile, and OperaMobile are supported. Other browsers are unknown

(2) Timeout setting

It feels bad when you send an AJAX request and get no response from the server. To alleviate this bad feeling, the XMLHttpRequest Level 2 specification provides us with an additional attribute and event listening event:

  • timeoutProperty: Sets the timeout in milliseconds.
  • timeoutEvent: Emitted when the response time exceeds the timeout property of the instance object;

The usage is as follows:

Xhr.timeout = 1000 xhr.ontimeout = () => {alert("Request did not return in a second.")}Copy the code

Note that when the request terminates, the onTimeout event handler is called, at which point the readyState property of XHR may have changed to 4, meaning that the onReadyStatechange event handler will continue to be called, However, accessing XHR’s status attribute after timeout aborts the request will cause the browser to throw an error, so you need to put a try-catch statement that checks the status attribute.

It’s a bit of a hassle, but we have more control over the XMLHttpRequest object.

Browser compatibility:

  • The desktop
    • Internet Explorer 10+ is supported by other browsers
  • The mobile terminal
    • Internet Explorer Mobile 10+ is supported with other browsers

OverrideMimeType (

The response header that is returned describes the MIME type of the returned data. By recognizing this type, the browser tells the XMLHttpRequest instance how to process the data. Sometimes, however (such as treating XML type data as plain text), we want to process the response data the way we want. In the XMLHttpRequest Level 2 specification, we can use the.overridemimeType () method, which is also easy to guess from the method name. This method overrides the MIME type of the data described in the response header.

It is written as follows:

const xhr = new XMLHttpRequest() xhr.open("get", "example.php", True) xhr.overridemimeType ("text/ XML ") // Forces the browser to interpret the response data as the specified type xhr.send(null)Copy the code

At this point, we are in control of how the response data is processed.

Browser compatibility:

  • The desktop
    • Internet Explorer 7+ is supported by other browsers
  • The mobile terminal
    • Firefox Mobile, Chrome for Android are supported, other browsers unknown

(iv) Progress events

The Progress Events specification is a working draft developed by the W3C. The specification defines a series of events related to client and server communication that listen to key points in the communication process, allowing us to control the details of the data transfer process with a finer granularity. There are currently six progress events that are triggered sequentially as data transfers progress (except for error and abort events). Let’s look at their definitions and browser compatibility:

  • loadstart: fired when the first byte of response data is received;
    • Desktop: Supported by all browsers except Safari Mobile
    • Mobile: Supported by all browsers except Safari Mobile
  • progress: triggered continuously during the receiving of a response;
    • Desktop: Internet Explorer 10+ is supported by other browsers
    • Mobile terminals: Both are supported
  • error: triggered when a request error occurs;
    • Desktop: supported by all browsers (source)
    • Mobile: supported by all browsers except IE Mobile (source)
  • abort: Again because of the callabort()Method when triggered;
    • Desktop: Unknown
    • Mobile: unknown
  • load: triggered when complete response data is received;
    • Desktop: Internet Explorer 7+ is supported by other browsers
    • Mobile: Chrome for Android, Edge, Firefox Mobile support, other browsers unknown
  • loadend: After communication is complete or triggerederror.abortorloadTrigger after event;
    • Desktop: Not supported by all browsers
    • Mobile: Not supported by all browsers

Here we will focus on the following two events:

(1) the load event

This event helps us save the readStatechange event. Instead of binding the event listener function to the XHR object instance to track changes in the readState property on the instance, we can simply use the following code:

const xhr = new XMLHttpRequest() xhr.onload = () => { if ((xhr.status >= 200 && xhr.status <300) || xhr.status == 304) {  alert(xhr.responseText) } else { alert("Something wrong!" ) } } xhr.open("get", "example.php", true) xhr.send(null)Copy the code

(2) the progress of the event

This event allowed us to achieve the desired loading progress bar effect. Because the onProgress event handler receives an Event object whose target attribute is an XHR object instance, it contains three additional attributes:

  • lengthComputable: Boolean value indicating whether progress information is available;
  • position: indicates the number of bytes currently received.
  • totalSize: indicates the expected number of bytes based on the content-Length response header.

Obviously, we have all the resources we need to load the progress bar, so we just need to write the following code:

const xhr = new XMLHttpRequest() xhr.onload = () => { if ((xhr.status >= 200 && xhr.status <300) || xhr.status == 304) {  alert(xhr.responseText) } else { alert("Something wrong!" Xhr.onprogress = function(event) {const divStatus = document.getelementById ("status") if (event.lengthComputable) { divStatus.innerHTML = `Received ${event.postion} of ${event.totalSize} bytes` } } xhr.open("get", "example.php", true) xhr.send(null)Copy the code

That’s it! Remember, however, that the onProgress event handler needs to be called before the.open() method.









Great, there’s nothing more I can say about AJAX, and if you’ve mastered all the concepts above, then you deserve the title of “AJAX Ninja.”

I’m really proud of you, Great Work! 🙌