共计 8186 个字符,预计需要花费 21 分钟才能阅读完成。
概述
Ajax(Asynchronous JavaScript and XML,即异步 JavaScript 和 XML)技术用于与服务器替换数据并刷新局部页面,实现更好的用户体验。
Ajax 的外围对象是 XMLHttpRequest
,通过 XMLHttpRequest
能够在不刷新页面的状况下申请特定 URL
,获取数据。由微软实现并在 IE5 中反对,用于执行异步网络申请。尽管 Ajax 是 Asynchronous JavaScript+XML 的缩写,但 Ajax 通信与数据格式无关,并不一定是 XML 格局。甚至反对 HTTP 以外的协定(如 file://
和 FTP
),只管可能受到更多出于平安等起因的限度。
应用 Ajax 须要几个步骤:
- 创立
XMLHttpRequest
对象。 - 收回
HTTP
申请。 - 接管服务器传回的数据。
- 更新网页数据。
总之,Ajax 就是通过 XMLHttpRequest
对象收回 HTTP
申请,失去服务器响应并解决。
创立 XMLHttpRequest
在所有古代浏览器都能够通过 XMLHttpRequest
构造函数创立 XHR 对象:
let xhr = new XMLHttpRequest();
而在老版本 IE5 和 IE6 中应用 ActiveX
对象创立:
let xhr = new ActiveXObject("Microsoft.XMLHTTP");
应用 XMLHttpRequest
创建对象后,须要应用 XHR 对象调用 open(type, url, async)
办法并设置三个参数:
- type:示意申请类型,如
"get"
、"post"
等。 - url:示意申请的 url。
- async:示意申请是否异步。如
true
示意异步申请,false
示意同步申请,它会使 JavaScript 代码期待服务器响应之后在继续执行。
GET
最罕用的 GET 申请办法,用于查问服务器信息。对于 XHR 对象而言,GET 申请的参数必须正确编码并增加到 URL 前面,而后再给 open()
办法。而最常见的谬误是格局不对。因而应用 encodeURIComponent()
对每个名 / 值进行编码,并且名 / 值对必须应用 &
分隔。如下所示:
xhr.open("get", "example.jsp?name1=value1&name2=value2", true);
能够应用以下函数将查问字符串参数增加到现有的 URL 开端:
function addURLParam(url, name, value) {url += (url.indexOf("?") == -1 ? "?" : "&"); | |
url += encodeURIComponent(name) + "=" + encodeURIComponent(value); | |
return url; | |
} |
能够应用这个函数构建申请 URL,如上面的例子所示:
let url = "example.jsp"; | |
// 增加参数 | |
url = addURLParam(url, "name", "Nicholas"); | |
url = addURLParam(url, "book", "Professional JavaScript"); | |
// 初始化申请 | |
xhr.open("get", url, false); |
这里应用 addURLParam()
函数能够保障通过 XMLHttpRequest
发送申请的 URL
格局正确。
这里的 example.jsp
是绝对地位,也能够应用相对 url
。并且 open()
只是为发送申请做筹备,而不发送申请。
定义好发送申请后,就能够调用 send(data)
办法,将申请发送到服务器。而 send(data)
办法要设置一个参数,是作为申请体发送的数据。不须要发送的话,传入null
。
xhr.send(null);
POST
而另一个申请办法就是 POST
申请,用于向服务器发送数据。每个 POST
申请都应在申请体中携带提交的数据。POST
申请体中能够蕴含十分多且是任意格局的数据。如下例子:
xhr.open("post", "example.jsp", true);
在传参上,POST
申请不必将参数增加在 URL
前面,而是应用 send()
办法将要发送的数据传入。
默认状况下,对服务器而言,POST
申请与 HTML
表单提交是不一样的。服务器逻辑须要读取原始 POST
数据能力获得浏览器发送的数据。不过,还能够应用 XML
模仿表单提交。为此,第一步须要把 Content-Type 头部设置为 “application/x-www-formurlencoded”,这是提交表单时应用的内容类型。第二步是创立对应格局的字符串。POST 数据此时应用与查问字符串雷同的格局。如果网页中的确有一个表单须要序列化并通过 XHR 发送到服务器,则能够应用 serialize()
函数来创立相应的字符串,如下所示:
function submitData() {let xhr = new XMLHttpRequest(); | |
xhr.onreadystatechange = function() {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("post", "postexample.jsp", true); | |
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); | |
// ID 为 user-info 的表单元素 | |
let form = document.getElementById("user-info"); | |
xhr.send(serialize(form)); | |
} |
留神:POST 申请相比 GET 申请要占用更多资源。从性能方面说,发送雷同数据的数据,GET 申请比 POST 申请快两倍。
响应
当服务器收到申请并响应后,XHR 对象会有以下属性被填充数据:
responseText
:作为响应体返回的文本。responseXML
:如果响应的内容类型是"text/xml"
或"application/xml"
,那就是蕴含响应数据的 XML DOM 文档。status
:响应的 HTTP 状态码。stautsText
:响应的 HTTP 状态形容。
个别都是通过 status
属性来确保响应是否胜利返回。当 status
为 2xx 示意胜利,为 304 示意资源未被批改,而是从缓存中取出的。这时的 responseText
或 responseXML
属性中会有内容。因而,咱们能够应用 status
属性来判断响应是否无效,如下所示:
xhr.open("get", "example.txt", false); | |
xhr.send(null); | |
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {console.log(xhr.responseText); | |
} else {console.log("Request was unsuccessful:" + xhr.status); | |
} |
属性和办法
readyState
XMLHttpRequest.readyState
属性返回一个无符号短整型数字,示意 XMLHttpRequest
对象的以后状态。该对象会返回以下某个值:
- 返回
0
,未初始化(Uninitialized),状态为UNSENT
。示意代理被创立,但尚未调用open()
办法。 - 返回
1
,状态为Open
已关上(Open),状态为OPENED
。示意open()
办法已被调用,但尚未调用send()
办法。 - 返回
2
,已发送(Sent),状态为HEADERS_RECEIVED
。示意已调用send()
办法,并且头部和状态曾经可取得,但尚未收到响应。 - 返回
3
:接管中(Receiving),状态为LOADING
。示意曾经收到局部响应。 - 返回
4
:已实现(Complete),状态为DONE
。示意申请操作已实现。意味着数据传输曾经彻底实现或失败。
通信过程中,每当 XMLHttpRequest
对象状态发送变动,readyState
属性值就会被扭转,并会触发 onreadystatechange
事件。并且 XMLHttpRequest
对象调用 abort()
办法,终止申请,也会造成 readyState
属性变动。为保障兼容性,onreadystatechange
事件应在 open()
办法之前赋值。如下所示:
let xhr = new XMLHttpRequest(); | |
xhr.onreadystatechange = function() {if (xhr.readyState == 4) {if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {console.log(xhr.responseText); | |
} else {alert("Request was unsuccessful:" + xhr.status); | |
} | |
} | |
}; | |
xhr.open("get", "example.txt", true); | |
xhr.send(null); |
如果之前应用的是异步申请并想在响应之前勾销,能够调用 abort()
办法:
let xhr = new XMLHttpRequest(); | |
xhr.open("get", "example.jsp", true); | |
setTimeout(function() {if (xhr) {xhr.abort(); | |
xhr = null; | |
} | |
}, 5000); // 5 秒后,终止 Ajax 申请 |
调用这个办法后,XMLHttpRequest
对象会进行触发事件,并阻止拜访这个对象上任何与响应相干的属性,而 readyState
属性变为 4
,status
属性变为 0
。中断请求后,应该勾销对 XMLHttpRequest
对象的援用。因为内存问题,不举荐重用 XMLHttpRequest
对象。
responseType
XMLHttpRequest.responseType
属性是一个字符串,返回响应数据的类型。容许手动设置返回数据的类型。如果设置为空字符串,则应用默认的 "text"
类型。
当 responseType
设置为一个特定的类型时,需确保服务器返回的类型和你所设置的类型是兼容的。如果不兼容,即便服务器返回了数据,数据也会变成null
。responseType
属性反对以下几种值:
""
:当responseType
为空字符串时,与text
雷同,示意服务器返回文本数据。"arraybuffer"
:示意服务器返回的是一个蕴含二进制数据的ArrayBuffer
对象。“blob”
:示意服务器返回的是一个蕴含二进制数据的Blob
对象。“document”
:示意服务器返回的是一个HTML Document
或XML Document
,这取决于接收数据的MIME
类型。“json”
:示意将接管到的服务器数据视为JSON
来进行解析并失去。“text”
:示意服务器返回的是以DOMString
对象示意的文本。
下面几种类型之中,text
类型适宜大多数状况,而且间接解决文本也比拟不便。document
类型适宜返回 HTML/XML
文档的状况,这意味着,对于那些关上 CORS 的网站,能够间接用 Ajax 抓取网页,而后不必解析 HTML 字符串,间接对抓取回来的数据进行 DOM 操作。blob
类型适宜读取二进制数据,比方图片文件。XMLHttpRequest.responseType
属性要在调用 open()
办法之后,并且在调用 send()
办法之前调用。
let xhr = new XMLHttpRequest(); | |
xhr.open("GET", "example.jsp", true); | |
xhr.responseType = "json"; | |
xhr.send(null); |
response
XMLHttpRequest.response
属性返回响应的数据体(即 HTTP 响应的 body
局部)。返回的类型为 ArrayBuffer
、Blob
、Document
、Object
或 DOMString
中的一个。具体类型由 XMLHttpRequest.responseType
类型决定。
当申请尚未实现或尚未胜利,该值为 null
。但当 responseType
属性设置成 "text"
或空字符串 (""
) 且当申请状态在LOADING
时,response
属性蕴含到目前为止该申请曾经获得的内容。
let xhr = new XMLHttpRequest(); | |
xhr.onreadystatechange = function() {if (xhr.readyState == 4) {console.log(xhr.response); | |
} | |
} |
HTTP 头部
在 HTTP 的每次申请和响应中都会携带一些头部字段,默认申请下,XMLHttpRequest
申请会发送以下头部字段。
Accept
:浏览器能够解决的内容类型。Accept-Charset
:浏览器能够显示的字符集。Accept-Encoding
:浏览器能够解决的压缩编码类型。Accept-Language
:浏览器应用的语言。Connection
:浏览器与服务器的连贯类型。Cookie
:页面中设置的Cookie
。Host
:发送申请的页面所在的域。Referer
:发送申请的页面的URI
。User-Agent
:浏览器的用户代理字符串。
XMLHttpRequest
对象通过一些办法裸露与申请和响应相干的头部字段。
然而 XMLHttpRequest
对象能够应用 setRequestHeader()
办法发送 HTTP 头部字段,接管两个参数:第一个参数是头部字段名,第二个参数是头部字段值。为保障申请头被发送,必须在 open()
之后,send()
之前调用。如果屡次调用,设同一个字段的值会合并成繁多的值发送。如下所示:
let xhr = new XMLHttpRequest(); | |
xhr.open("get", "example.jsp", true); | |
xhr.setRequestHeader("Content-Type", "application/json"); | |
xhr.setRequestHeader("Custom-Header", "Custom-Value"); | |
xhr.send(null); |
自定义头部要区别于浏览器失常发送的头部,否则会影响服务器失常响应。默认头部在有些浏览器上能够重写。
getResponseHeader()
办法能够返回 HTTP 头部信息中指定的字段值,接管的参数为头部名称。也能够应用 getAllResponseHeaders()
办法获取所有,返回的可能是如下所示的字符串:
Date: Sun, 14 Nov 2004 18:04:03 GMT | |
Server: Apache/1.3.29 (Unix) | |
Vary: Accept | |
X-Powered-By: PHP/4.3.8 | |
Connection: close | |
Content-Type: text/html; charset=iso-8859-1 |
通过解析以上头部字段的输入,就能够晓得服务器发送的所有头部,而不须要独自去查看了。
XMLHttpRequest Level 2
XMLHttpRequest Level 2
是在 XMLHttpRequest Level 1
的根底上进一步的扩大。但并非所有浏览器都实现了 XMLHttpRequest Level 2
的所有性能,也可能只实现了局部性能。
FormData
在 XMLHttpRequest Level 2
中新增了 FormData
类型,次要用于将数据编译成键值对,应用 XMLHttpRequest
来发送数据。也用于创立与表单相似格局的数据。创立一个 FormData
对象,如下所示:
let data = new FormData(); | |
data.append("username", "Clark"); | |
data.append("account", "addie"); | |
let request = new XMLHttpRequest(): | |
request.open("post", "http://example.com/submitform.jsp"); | |
request.send(data); |
append()
办法接管两个参数:键,相当于表单字段名;值,相当于表单字段名的值。当然,也能够间接给 FormData
构造函数传入表单元素,也能够将表单中的数据作为键值对填充进去,也能够附加额定的数据到 FormData
对象中:
let form = document.querySelector("form"); | |
let data = new FormData(form); | |
data.append("serialnumber", 134); |
而应用 FormData
之后,能够不再须要给 XMLHttpRequest
对象显式地设置任何申请头部。XMLHttpRequest
对象可能辨认作为 FormData
对象传入的数据类型并主动配置相应的头部。
timeout
XMLHttpRequest.timeout
属性是一个无符号长整型数,示意发送数据后期待的毫秒数,响应不胜利则中断请求。是 IE8 给 XMLHttpRequest
对象增加的属性,并在 XMLHttpRequest Level 2
中增加了该个性。默认值为 0
,当超时时,就会触发 timeout
事件。如下所示:
let xhr = new XMLHttpRequest(); | |
xhr.onreadystatechange = function() {if (xhr.readyState == 4) { | |
try {if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {alert(xhr.responseText); | |
} else {alert("Request was unsuccessful:" + xhr.status); | |
} | |
} catch (ex) {// 假如由 ontimeout 解决} | |
} | |
}; | |
xhr.open("get", "timeout.php", true); | |
xhr.timeout = 1000; // 设置 1 秒超时 | |
xhr.ontimeout = function() {alert("Request did not return in a second."); | |
}; | |
xhr.send(null); |
这个例子演示了应用 timeout
设置超时。给 timeout
设置 1000 毫秒意味着,如果申请没有在 1 秒钟内返回则会中断。此时则会触发 ontimeout
事件处理程序,readyState
依然会变成 4,因而也会调用 onreadystatechange
事件处理程序。不过,如果在超时之后拜访 status
属性则会产生谬误。为做好防护,能够把查看 status
属性的代码封装在 try/catch
语句中。
overrideMimeType()
XMLHttpRequest.overrideMimeType()
办法用来重写 XMLHttpRequest
响应的 MIME
类型。是 Firefox 首次引入,在 XMLHttpRequest Level 2
中增加了该办法。因为响应返回的 MIME
类型决定了 XMLHttpRequest
对象如何解决响应。例如服务器理论发送的是 XML
数据,但响应头中 MIME
类型设置的是 text/plain
,浏览器不会主动解析,responseXML
属性值是null
。此时调用overrideMimeType()
能够保障将响应当成 XML
而不是纯文原本解决:
let xhr = new XMLHttpRequest(); | |
xhr.open("get", "example.jsp", true); | |
xhr.overrideMimeType("text/xml"); | |
xhr.send(null); |
留神:为正确笼罩响应的 MIME
类型,该办法必须在 send()
办法之前调用。
小结
Ajax 是无需刷新以后页面即可从服务器获取数据的一种办法,其中外围对象是 XMLHttpRequest
,最早由微软创造,并在 IE5 中引入。之后,其它浏览器都实现了该对象。W3C 尽管也引入了 Web 规范。尽管不同浏览器有些差别,但根本应用时绝对较标准的,因而能够放心使用。
如果想要查看更多文章,请关注公总号「海人的博客」