The XMLHttpRequest object
Introduction to the
The browser communicates with the server over HTTP. When a user types a web address into the browser’s address bar or submits content to the server through a web form, the browser makes an HTTP request to the server.
In 1999, Microsoft released Version 5.0 of Internet Explorer, which for the first time introduced a new feature that allowed JavaScript scripts to make HTTP requests to the server. The feature didn’t get much attention until the launch of Gmail in 2004 and Google Map in 2005. The term AJAX was first formally introduced in February 2005, and is an abbreviation for Asynchronous JavaScript and XML, referring to the Asynchronous communication of JavaScript to fetch data from an XML document from a server and update the corresponding portion of the current web page. Instead of refreshing the entire page. Later, the term AJAX became synonymous with HTTP communication initiated by JavaScript scripts, meaning that any communication initiated by a script could be called AJAX communication. The W3C also published its international standard in 2006.
Specifically, AJAX involves the following steps.
- Create an instance of XMLHttpRequest
- Making an HTTP request
- Receive data returned by the server
- Update web data
In a nutshell, AJAX makes HTTP requests through native XMLHttpRequest objects, gets the data returned by the server, and then processes it. Today, the server returns JSON data, and XML is obsolete, but the name AJAX has become a generic term that has lost its literal meaning.
The XMLHttpRequest object is the primary interface of AJAX for communication between the browser and the server. Despite XML and Http in its name, it can actually use multiple protocols (such as File or FTP) to send data in any format (both string and binary).
XMLHttpRequest is itself a constructor that generates instances using the new command. It has no parameters.
var xhr = new XMLHttpRequest();
Copy the code
Once you create an instance, you can use the open() method to specify some of the details of establishing an HTTP connection.
xhr.open('GET'.'http://www.example.com/page.php'.true);
Copy the code
The above code specifies the use of the GET method to establish a connection to the specified server url. The third argument, true, indicates that the request is asynchronous.
You then specify a callback function that listens for changes in communication state (the readyState property).
xhr.onreadystatechange = handleStateChange;
function handleStateChange() {
// ...
}
Copy the code
In the above code, the listener function handleStateChange is called whenever the state of the XMLHttpRequest instance changes
Finally, the send() method is used to actually issue the request.
xhr.send(null);
Copy the code
In the above code, the send() parameter is null, indicating that the request is sent with no data body. If you are sending a POST request, you need to specify the data body here.
Once you get the data back from the server, AJAX doesn’t refresh the entire web page, but updates only the relevant parts of the web page without interrupting what the user is doing.
Note that AJAX can only make HTTP requests to same-origin sites (all with the same protocol, domain name, and port), and if it makes cross-domain requests, an error will be reported (see the same-Origin Policy and CORS Communications chapters).
Below is a complete example of a simple use of the XMLHttpRequest object.
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
// If the communication succeeds, the status value is 4
if (xhr.readyState === 4) {if (xhr.status === 200) {console.log(xhr.responseText);
} else {
console.error(xhr.statusText); }}}; xhr.onerror =function (e) {
console.error(xhr.statusText);
};
xhr.open('GET'.'/endpoint'.true);
xhr.send(null);
Copy the code
Instance property of XMLHttpRequest
XMLHttpRequest.readyState
XMLHttpRequest. ReadyState returns an integer, represent the current state of the instance objects. This property is read-only. It may return the following values.
- 0: indicates that the XMLHttpRequest instance has been generated, but the instance’s
open()
Method has not been called yet. - 1, said
open()
Method has been called, but the instance’ssend()
Method has not yet been called and the instance can still be usedsetRequestHeader()
Method to set the HTTP request header. - 2, for instance
send()
Method has been called, and the header and status code returned by the server have been received. - 3: indicates that the body part of the data is being received from the server. In this case, if the instance
responseType
Attribute is equal to thetext
Or an empty string,responseText
Property will contain some of the information already received. - 4: indicates that the data returned by the server is fully received or the data receiving fails.
Whenever the instance object changes state during communication, its readyState property changes value. Each time this value changes, the readyStateChange event is triggered.
var xhr = new XMLHttpRequest();
if (xhr.readyState === 4) {
// The request ends, processing the data returned by the server
} else {
// "Loading......" is displayed.
}
Copy the code
In the code above, xhr.readyState equals 4, indicating that the HTTP request made by the script is complete. In other cases, the HTTP request is still in progress.
XMLHttpRequest.onreadystatechange
XMLHttpRequest. The onreadystatechange property to a monitoring function. This property is executed when the readyStatechange event occurs (the readyState property of the instance changes).
In addition, if you use instances of the abort () method to terminate the XMLHttpRequest request, also can cause the readyState attribute changes, leading to call XMLHttpRequest. The onreadystatechange property.
Here’s an example.
var xhr = new XMLHttpRequest();
xhr.open( 'GET'.'http://example.com' , true );
xhr.onreadystatechange = function () {
if(xhr.readyState ! = =4|| xhr.status ! = =200) {
return;
}
console.log(xhr.responseText);
};
xhr.send();
Copy the code
XMLHttpRequest.response
The xmlHttprequest.Response attribute represents the body of data returned by the server (that is, the body part of the HTTP response). It can be any data type, such as string, object, binary objects, etc., specific types of XMLHttpRequest. ResponseType attribute decision. The xmlHttprequest. response attribute is read-only.
This property is equal to null if the request is unsuccessful or the data is incomplete. However, if the responseType property is equal to text or an empty string, the response property contains some of the data that the server has returned before the request ends (at the stage where readyState is equal to 3).
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) { handler(xhr.response); }}复制代码
XMLHttpRequest.responseType
XMLHttpRequest.responseType
属性是一个字符串,表示服务器返回数据的类型。这个属性是可写的,可以在调用open()
方法之后、调用send()
方法之前,设置这个属性的值,告诉浏览器如何解读返回的数据。如果responseType
设为空字符串,就等同于默认值text
。
XMLHttpRequest.responseType
属性可以等于以下值。
- “”(空字符串):等同于
text
,表示服务器返回文本数据。 - “arraybuffer”:ArrayBuffer 对象,表示服务器返回二进制数组。
- “blob”:Blob 对象,表示服务器返回二进制对象。
- “document”:Document 对象,表示服务器返回一个文档对象。
- “json”:JSON 对象。
- “text”:字符串。
上面几种类型之中,text
类型适合大多数情况,而且直接处理文本也比较方便。document
类型适合返回 HTML / XML 文档的情况,这意味着,对于那些打开 CORS 的网站,可以直接用 Ajax 抓取网页,然后不用解析 HTML 字符串,直接对抓取回来的数据进行 DOM 操作。blob
类型适合读取二进制数据,比如图片文件。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status === 200) {
var blob = new Blob([xhr.response], {type: 'image/png'});
// 或者
var blob = xhr.response;
}
};
xhr.send();
复制代码
如果将这个属性设为ArrayBuffer
,就可以按照数组的方式处理二进制数据。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
var uInt8Array = new Uint8Array(this.response);
for (var i = 0, len = uInt8Array.length; i < len; ++i) {
// var byte = uInt8Array[i];
}
};
xhr.send();
复制代码
如果将这个属性设为json
,浏览器就会自动对返回数据调用JSON.parse()
方法。也就是说,从xhr.response
属性(注意,不是xhr.responseText
属性)得到的不是文本,而是一个 JSON 对象。
XMLHttpRequest.responseText
XMLHttpRequest.responseText
属性返回从服务器接收到的字符串,该属性为只读。只有 HTTP 请求完成接收以后,该属性才会包含完整的数据。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);
xhr.responseType = 'text';
xhr.onload = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send(null);
复制代码
XMLHttpRequest.responseXML
XMLHttpRequest.responseXML
属性返回从服务器接收到的 HTML 或 XML 文档对象,该属性为只读。如果本次请求没有成功,或者收到的数据不能被解析为 XML 或 HTML,该属性等于null
。
该属性生效的前提是 HTTP 回应的Content-Type
头信息等于text/xml
或application/xml
。这要求在发送请求前,XMLHttpRequest.responseType
属性要设为document
。如果 HTTP 回应的Content-Type
头信息不等于text/xml
和application/xml
,但是想从responseXML
拿到数据(即把数据按照 DOM 格式解析),那么需要手动调用XMLHttpRequest.overrideMimeType()
方法,强制进行 XML 解析。
该属性得到的数据,是直接解析后的文档 DOM 树。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);
xhr.responseType = 'document';
xhr.overrideMimeType('text/xml');
xhr.onload = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseXML);
}
};
xhr.send(null);
复制代码
XMLHttpRequest.responseURL
XMLHttpRequest.responseURL
属性是字符串,表示发送数据的服务器的网址。
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/test', true);
xhr.onload = function () {
// 返回 http://example.com/test
console.log(xhr.responseURL);
};
xhr.send(null);
复制代码
注意,这个属性的值与open()
方法指定的请求网址不一定相同。如果服务器端发生跳转,这个属性返回最后实际返回数据的网址。另外,如果原始 URL 包括锚点(fragment),该属性会把锚点剥离。
XMLHttpRequest.status,XMLHttpRequest.statusText
XMLHttpRequest.status
属性返回一个整数,表示服务器回应的 HTTP 状态码。一般来说,如果通信成功的话,这个状态码是200;如果服务器没有返回状态码,那么这个属性默认是200。请求发出之前,该属性为0
。该属性只读。
- 200, OK,访问正常
- 301, Moved Permanently,永久移动
- 302, Moved temporarily,暂时移动
- 304, Not Modified,未修改
- 307, Temporary Redirect,暂时重定向
- 401, Unauthorized,未授权
- 403, Forbidden,禁止访问
- 404, Not Found,未发现指定网址
- 500, Internal Server Error,服务器发生错误
基本上,只有2xx和304的状态码,表示服务器返回是正常状态。
if (xhr.readyState === 4) {
if ( (xhr.status >= 200 && xhr.status < 300)
|| (xhr.status === 304) ) {
// 处理服务器的返回数据
} else {
// 出错
}
}
复制代码
XMLHttpRequest.statusText
属性返回一个字符串,表示服务器发送的状态提示。不同于status
属性,该属性包含整个状态信息,比如“OK”和“Not Found”。在请求发送之前(即调用open()
方法之前),该属性的值是空字符串;如果服务器没有返回状态提示,该属性的值默认为“OK”。该属性为只读属性。
XMLHttpRequest. A timeout, XMLHttpRequestEventTarget ontimeout
The xmlHttprequest. timeout property returns an integer indicating how many milliseconds will pass before the request terminates automatically if no result is received. If this property is equal to 0, there is no time limit.
XMLHttpRequestEventTarget. Ontimeout property is used to set up a monitoring function, in the event of a timeout event, will carry out the monitoring function.
Here’s an example.
var xhr = new XMLHttpRequest();
var url = '/server';
xhr.ontimeout = function () {
console.error('The request for ' + url + ' timed out.');
};
xhr.onload = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// Process the data returned by the server
} else {
console.error(xhr.statusText); }}}; xhr.open('GET', url, true);
// Specify a 10-second timeout
xhr.timeout = 10 * 1000;
xhr.send(null);
Copy the code
Event listener property
The XMLHttpRequest object can specify listener functions for the following events.
- XMLHttpRequest. Onloadstart: loadstart events (HTTP requests) to monitor function
- XMLHttpRequest. Onprogress: progress events (is sending and load data) surveillance function
- Xmlhttprequest. onabort: Abort event (the request aborts, for example, when the user calls
abort()
Method) - Xmlhttprequest. onError: A listener for error events (failed requests)
- Xmlhttprequest. onload: A listener for the load event (the request completed successfully)
- Xmlhttprequest. onTIMEOUT: A listener for the timeout event (when a user-specified time limit has expired and the request has not completed)
- Xmlhttprequest. onloadEnd: A listener function for the loadEnd event (request completion, regardless of success or failure)
Here’s an example.
xhr.onload = function() {
var responseText = xhr.responseText;
console.log(responseText);
// process the response.
};
xhr.onabort = function () {
console.log('The request was aborted');
};
xhr.onprogress = function (event) {
console.log(event.loaded);
console.log(event.total);
};
xhr.onerror = function() {
console.log('There was an error! ');
};
Copy the code
The listener function for the Progress event takes an event object parameter that has three attributes: the Loaded attribute returns the amount of data that has been transferred, the total attribute returns the total amount of data, and the lengthComputable attribute returns a Boolean value indicating whether the progress of the load is computable. Of all these listener functions, only the listener of the Progress event has parameters. The other functions have no parameters.
Note that the onError event does not get an error message if a network error occurs (such as a server that cannot connect). That is, there may be no error object, so only an error message is displayed.
XMLHttpRequest.withCredentials
XMLHttpRequest. WithCredentials attribute is a Boolean value, said cross-domain request, the user information (such as cookies and certification of HTTP headers) is included in the request, the default is false, that is, when sending the cross-domain request to example.com, Cookies, if any, that example.com sets on this machine are not sent.
If you need to send cookies across domain AJAX requests, you need to set the withCredentials attribute to true. Note that same-origin requests do not need to set this property.
var xhr = new XMLHttpRequest();
xhr.open('GET'.'http://example.com/'.true);
xhr.withCredentials = true;
xhr.send(null);
Copy the code
For this attribute to take effect, the server must explicitly return the access-Control-allow-credentials header.
Access-Control-Allow-Credentials: true
Copy the code
When the withCredentials attribute is enabled, cross-domain requests not only send cookies, but also set cookies specified by the remote host. The reverse is also true; if the withCredentials attribute is not enabled, cross-domain AJAX requests will be ignored even if they explicitly ask the browser to set cookies.
Note that scripts always comply with the same-origin policy and cannot read cross-domain cookies from the document.cookie or HTTP response headers. The withCredentials attribute does not affect this.
XMLHttpRequest.upload
XMLHttpRequest can send not only requests, but also files, called AJAX file uploads. After you send the file, you can watch the progress of the upload by viewing an object that you get through the xmlHttprequest.upload attribute. The main method is to listen for various events on this object: loadStart, loadEnd, load, abort, error, progress, timeout.
Suppose there is a
<progress min="0" max="100" value="0">0% complete</progress>
Copy the code
When a file is uploaded, you can obtain the progress of the upload by specifying a listener function for the Progress event on the Upload attribute.
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST'.'/server'.true);
xhr.onload = function (e) {};
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
// Compatible with older browsers that do not support progressBar.textContent = progressBar.value; }}; xhr.send(blobOrFile); } upload(new Blob(['hello world'] and {type: 'text/plain'}));
Copy the code
Instance method of XMLHttpRequest
XMLHttpRequest.open()
The xmlHttprequest.open () method is used to specify the parameters of the HTTP request, or to initialize the XMLHttpRequest instance object. It can take a total of five arguments.
void open(
string method,
string url,
optional boolean async,
optional string user,
optional string password
);
Copy the code
method
: represents HTTP verb methods, such asGET
,POST
,PUT
,DELETE
,HEAD
And so on.url
: indicates the destination URL of the request.async
: Boolean value indicating whether the request is asynchronous. The default value istrue
. If set tofalse
,send()
The method does not proceed to the next step until it receives a result from the server. This parameter is optional. Since synchronizing AJAX requests can cause the browser to lose response, many browsers have banned it from the main thread and only allow it in the Worker. Therefore, this parameter should easily not be set tofalse
.user
: indicates the user name used for authentication. The default value is an empty string. This parameter is optional.password
: indicates the password used for authentication. The default value is an empty string. This parameter is optional.
Note that if you use this method again on an AJAX request that used the open() method, you are calling abort(), which terminates the request.
The following is an example of sending a POST request.
var xhr = new XMLHttpRequest();
xhr.open('POST'.encodeURI('someURL'));
Copy the code
XMLHttpRequest.send()
The xmlHttprequest.send () method is used to actually issue the HTTP request. Its parameters are optional. If there is no parameter, the HTTP request has only one URL and no data body. A typical example is GET request. If it has a parameter, it contains a body of information that contains specific data in addition to the header information, a typical example being a POST request.
Here is an example of a GET request.
var xhr = new XMLHttpRequest();
xhr.open('GET'.'http://www.example.com/?id=' + encodeURIComponent(id),
true
);
xhr.send(null);
Copy the code
In the code above, the parameters of the GET request are appended to the URL as a query string.
Here is an example of sending a POST request.
var xhr = new XMLHttpRequest();
var data = 'email='
+ encodeURIComponent(email)
+ '&password='
+ encodeURIComponent(password);
xhr.open('POST'.'http://www.example.com'.true);
xhr.setRequestHeader('Content-Type'.'application/x-www-form-urlencoded');
xhr.send(data);
Copy the code
Note that all XMLHttpRequest listening events must be set before the send() method is called.
The parameters of the SEND method are the data to be sent. Data in a variety of formats can be used as its parameters.
void send();
void send(ArrayBufferView data);
void send(Blob data);
void send(Document data);
void send(String data);
void send(FormData data);
Copy the code
If send() sends a DOM object, the data is serialized before it is sent. If you’re sending binary data, it’s better to send an ArrayBufferView or Blob object, which makes uploading files via Ajax possible.
Here is an example of sending form data. The FormData object can be used to construct FormData.
var formData = new FormData();
formData.append('username'.'Joe');
formData.append('email'.'[email protected]');
formData.append('birthDate'.1940);
var xhr = new XMLHttpRequest();
xhr.open('POST'.'/register');
xhr.send(formData);
Copy the code
In the code above, the FormData object constructs the FormData and then sends it using the send() method. It has the same effect as sending the form data below.
<form id='registration' name='registration' action='/register'>
<input type='text' name='username' value='Joe'>
<input type='email' name='email' value='[email protected]'>
<input type='number' name='birthDate' value='1940'>
<input type='submit' onclick='return sendForm(this.form); '>
</form>
Copy the code
The following example uses a FormData object to process FormData and then send it.
function sendForm(form) {
var formData = new FormData(form);
formData.append('csrf'.'e69a18d7db1286040586e6da1950128c');
var xhr = new XMLHttpRequest();
xhr.open('POST', form.action, true);
xhr.onload = function() {
// ...
};
xhr.send(formData);
return false;
}
var form = document.querySelector('#registration');
sendForm(form);
Copy the code
XMLHttpRequest.setRequestHeader()
XMLHttpRequest. SetRequestHeader () method is used to set the browser sends an HTTP request header information. This method must be called after open() but before send(). If the method is called multiple times, setting the same field, the values from each call are combined into a single value and sent.
The method takes two arguments. The first argument is a string that represents the field name of the header information, and the second argument is the field value.
xhr.setRequestHeader('Content-Type'.'application/json');
xhr.setRequestHeader('Content-Length'.JSON.stringify(data).length);
xhr.send(JSON.stringify(data));
Copy the code
The above code first sets the header content-Type, which means to send JSON data. Then set content-Length to the Length of the data. Finally, the JSON data is sent.
XMLHttpRequest.overrideMimeType()
XMLHttpRequest. OverrideMimeType () method is used to specify the MIME type, cover the MIME type returned by the server really, so that the browser for different processing. For example, if the server returns data of type TEXT/XML, for some reason the browser fails to parse the data and fails to retrieve the data. To retrieve the raw data, we can change the MIME type to text/plain so that the browser doesn’t parse it automatically and we can retrieve the original text.
xhr.overrideMimeType('text/plain')
Copy the code
Note that this method must be called before the send() method.
Changing the data type returned by the server is not the way you would normally do it. If you want the server to return the specified data type, you can tell the server with the responseType property, as in the following example. Use the overrideMimeType() method only if the server is unable to return a certain data type.
var xhr = new XMLHttpRequest();
xhr.onload = function(e) {
var arraybuffer = xhr.response;
// ...
}
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.send();
Copy the code
XMLHttpRequest.getResponseHeader()
XMLHttpRequest. GetResponseHeader () method returns the HTTP header to specify the value of the field, if haven’t received the server response or specified field does not exist, returns null. The method’s arguments are case insensitive.
function getHeaderTime() {
console.log(this.getResponseHeader("Last-Modified"));
}
var xhr = new XMLHttpRequest();
xhr.open('HEAD'.'yourpage.html');
xhr.onload = getHeaderTime;
xhr.send();
Copy the code
If there are multiple fields with the same name, their values are concatenated into a single string, separated by commas and Spaces.
XMLHttpRequest.getAllResponseHeaders()
XMLHttpRequest. The getAllResponseHeaders () method returns a string, said all the HTTP header information from the server. The format is a string. Each header is separated by CRLF (carriage return + line feed). If no response is received from the server, this property is null. If a network error occurs, this property is an empty string.
var xhr = new XMLHttpRequest();
xhr.open('GET'.'foo.txt'.true);
xhr.send();
xhr.onreadystatechange = function () {
if (this.readyState === 4) {
varheaders = xhr.getAllResponseHeaders(); }}Copy the code
The code above is used to get all the header information returned by the server. It could be a string like this.
date: Fri, 08 Dec 2017 21:04:30 GMT\r\n
content-encoding: gzip\r\n
x-content-type-options: nosniff\r\n
server: Meinheld / 0.6.1 \ r \ nx-frame-options: DENY\r\n
content-type: text/html; charset=utf-8\r\n
connection: keep-alive\r\n
strict-transport-security: max-age=63072000\r\n
vary: Cookie, Accept-Encoding\r\n
content-length: 6502\r\n
x-xss-protection: 1; mode=block\r\n
Copy the code
The string is then processed.
var arr = headers.trim().split(/[\r\n]+/);
var headerMap = {};
arr.forEach(function (line) {
var parts = line.split(':');
var header = parts.shift();
var value = parts.join(':');
headerMap[header] = value;
});
headerMap['content-length'] / / "6502"
Copy the code
XMLHttpRequest.abort()
The xmlHttprequest.abort () method is used to abort an HTTP request that has already been made. When this method is called, the readyState property changes to 4 and the status property to 0.
var xhr = new XMLHttpRequest();
xhr.open('GET'.'http://www.example.com/page.php'.true);
setTimeout(function () {
if (xhr) {
xhr.abort();
xhr = null; }},5000);
Copy the code
The code above terminates an AJAX request after 5 seconds.
Event of the XMLHttpRequest instance
ReadyStateChange event
The readyStateChange event is triggered when the value of the readyState property changes.
We can use the onReadyStateChange property to specify a listener for this event, and to handle different states differently. In particular, when the status changes to 4, the communication is successful and the callback function can process the data sent back from the server.
Progress events
When a file is uploaded, both the XMLHttpRequest instance object itself and the instance’s Upload property have a progress event that continuously returns the progress of the upload.
var xhr = new XMLHttpRequest();
function updateProgress (oEvent) {
if (oEvent.lengthComputable) {
var percentComplete = oEvent.loaded / oEvent.total;
} else {
console.log('Unable to calculate progress');
}
}
xhr.addEventListener('progress', updateProgress);
xhr.open();
Copy the code
Load events, error events, and abort events
The LOAD event indicates that data from the server is received, the ERROR event indicates that the request fails, and the abort event indicates that the request is interrupted (for example, the user cancels the request).
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', transferComplete);
xhr.addEventListener('error', transferFailed);
xhr.addEventListener('abort', transferCanceled);
xhr.open();
function transferComplete() {
console.log('Data received completed');
}
function transferFailed() {
console.log('Data receiving error');
}
function transferCanceled() {
console.log('User unsubscribe');
}
Copy the code
Loadend event
Abort, Load, and ERROR are accompanied by a loadEnd event, indicating that the request ends without knowing whether it succeeded.
xhr.addEventListener('loadend', loadEnd);
function loadEnd(e) {
console.log('Request ended, status unknown');
}
Copy the code
A timeout event
A timeout event is emitted when the server does not return a result after the specified time, as shown in the Timeout properties section.
Navigator.sendBeacon()
When users uninstall a web page, they sometimes need to send some data to the server. It is natural to use the XMLHttpRequest object to send data inside the listener function for the Unload event or beforeUnload event. However, this is not very reliable, because the XMLHttpRequest object is sent asynchronously, and it is very likely that the page will be unloaded before it is sent, causing the send to cancel or fail.
The solution is to add some time-consuming synchronization operations to the Unload event. This allows enough time for the asynchronous AJAX to send successfully.
function log() {
let xhr = new XMLHttpRequest();
xhr.open('post'.'/log'.true);
xhr.setRequestHeader('Content-Type'.'application/x-www-form-urlencoded');
xhr.send('foo=bar');
}
window.addEventListener('unload'.function(event) {
log();
// a time-consuming operation
for (let i = 1; i < 10000; i++) {
for (let m = 1; m < 10000; m++) { continue; }}});Copy the code
In the code above, a double loop is forced, lengthening the execution time of the UNLOAD event and causing the asynchronous AJAX to send successfully.
Similarly, you can use setTimeout. Here is an example of tracking user clicks.
// The HTML code is as follows
// <a id="target" href="https://baidu.com">click</a>
const clickTime = 350;
const theLink = document.getElementById('target');
function log() {
let xhr = new XMLHttpRequest();
xhr.open('post'.'/log'.true);
xhr.setRequestHeader('Content-Type'.'application/x-www-form-urlencoded');
xhr.send('foo=bar');
}
theLink.addEventListener('click'.function (event) {
event.preventDefault();
log();
setTimeout(function () {
window.location.href = theLink.getAttribute('href');
}, clickTime);
});
Copy the code
The code above uses setTimeout and takes 350 milliseconds to jump to the page, thus giving the asynchronous AJAX time to emit.
The common problem with all of these practices is that the load time is too long, the loading of subsequent pages is delayed, and the user experience is not good.
To solve this problem, browsers introduced the navigator.sendbeacon () method. This approach still makes the request asynchronously, but decouple the request from the current page thread as a task for the browser process, thus ensuring that the data is sent out without delaying the unload process.
window.addEventListener('unload', logData, false);
function logData() {
navigator.sendBeacon('/log', analyticsData);
}
Copy the code
The navigator. sendBeacon method takes two parameters, the first is the URL of the target server and the second is the data to be sent (optionally), which can be of any type (string, form object, binary object, and so on).
navigator.sendBeacon(url, data)
Copy the code
The return value from this method is a Boolean, true on success, false otherwise.
The HTTP method for sending data is POST, which can cross domains, similar to a form submitting data. It cannot specify a callback function.
Here’s an example.
// The HTML code is as follows
// <body onload="analytics('start')" onunload="analytics('end')">
function analytics(state) {
if(! navigator.sendBeacon)return;
var URL = 'http://example.com/analytics';
var data = 'state=' + state + '&location=' + window.location;
navigator.sendBeacon(URL, data);
}
Copy the code