现在最流行的获取后端的(浏览器从服务器)数据的方式就是通过Ajax了吧。今天就来详细的来学习下这个知识吧。如果使用ajax来访问后段的数据,浏览器和浏览器端的js做了那些工作呢?我做了一个图,请大家看一下:
1.原生js的Ajax请求的方式
由上面的图我们大致的知道了ajax访问后端数据的一个过程。最重要的就是检测浏览器,创建XMLHttpRequest
对象的过程:
代码如下:
<code class="hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/* 判断是否支持XMLHttpRequest */</span> <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">createXHR</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typeof</span> XMLHttpRequest != <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"undefined"</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> XMLHttpRequest(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typeof</span> ActiveXobject != <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"undefined"</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typeof</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">arguments</span>.callee.activeXString != <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'string'</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> versions = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"MSXML2.XMLHttp.6.0"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"MSXML2.XMLHttp.3.0"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"MSXML2.XMLHttp"</span>], i, len; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, len = versions.length; i < len; i++) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ActiveXObject(versions[i]); <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">arguments</span>.callee.activeXString = versions[i]; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (ex) { console.log(ex); } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ActiveXObject(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">arguments</span>.callee.activeXString()); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Error</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'no XHR'</span>) } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>
此处分别是根据浏览器是否支持XMLHttpRequest
对象来判断是否是IE还是非IE,然后来创建响应的对象。
当XHR对象open()
的时候,此时并没有向Web服务器发送HTTP请求,而是当send()
的时候,XHR对象才向Web服务器发送请求。
<code class="hljs perl has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">xhr.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">send</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
这里有一个非常重要的地方,就是send
的参数为null
。
send()
方法接收一个参数,需要作为请求主体发送的数据。如果不需要作为请求主体发送数据,则必须传入null,因为这个参数对于某些浏览器是必须的。
当浏览器接收到Web服务器的响应后,会开始填充XHR对象的属性,主要的如下:
responseText
作为响应的主体被返回的文本responseXML
如果响应的内容类型为text/xml
或者application/xml
这个属性中将包含着响应数据的XML
DOM
文档status
响应的HTTP状态-
statusText
HTTP状态的说明一般通过
XHR.status
属性值为200
表示成功的标志。此时可以获取responseText
和responseXML
的值。当XHR.status==304
(响应是有效的)的时候,说明文件没有被修改,可以直接使用浏览器缓存的版本。
检测的代码如下:
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">if (xhr<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.status</span> >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span> && xhr<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.status</span> <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">300</span> || xhr<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.status</span> == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">304</span>) { console<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.log</span>(xhr<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.responseText</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> } else { console<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.log</span>(xhr<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.responseText</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
不要依赖
responseText
,因为在跨浏览器处理的时候这个属性获取的值是不可靠的。
上面的代码在同步发送请求验证和获取返会的数据是没有任何问题的。但是当我们发送异步请求的时候确实会出现问题,因为我们不知道服务端的Response
在什么时候反回。那么我们该怎么办呢?
其实在ajax在向Web服务器发送请求的时候,会有一个readyState属性来检测XHR对象的请求/响应过程的当前活动阶段
,值的列表如下:
0
未初始化。尚未调用open()
方法1
启动。已经调用open()
方法,但是尚未调用send()
方法2
发送。已经调用send()
方法。但是还没有接收到响应。3
接收。已经接收到部分的响应数据。-
4
完成。已经接收到全部的响应数据,而且已经在客户端可以使用了。每当
XHR.readyState
的属性值发生变化,都会触发一次onreadystatechange
事件。通常我们只对XHR.readyState==4
的时候感兴趣(这时数据已经全部就绪)。
必须在调用
open()
之前指定onreadystatechange
事件处理程序才能够保证夸浏览器的兼容性。
实例代码如下:
<code class="hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> xhr = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> createXHR(); xhr.onreadystatechange = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (xhr.readyState == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (xhr.status >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span> && xhr.status <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">300</span> || xhr.status == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">304</span>) { console.log(xhr.responseText); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//console.log(xhr.)</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//document.createElement()</span> creatNode(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'script'</span>); creatNode(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'img'</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { console.log(xhr.responseText); } } } xhr.open(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'GET'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'test.js'</span>, <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>); xhr.send(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">''</span>); </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
2.jQuery发送Ajax的方式
参考jquery的文档,使用jquery来发送ajax请求比原生的js简单很多。如下代码:
2.1GET方式
<code class="hljs css has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">$<span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.ajax</span>(<span class="hljs-rules" style="box-sizing: border-box;">{ <span class="hljs-rule" style="box-sizing: border-box;"><span class="hljs-attribute" style="box-sizing: border-box;">type</span>:<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 102, 102);"> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"GET"</span>, url: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"test.js"</span>, dataType: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"script"</span> </span></span></span>});</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
2.2POST方式
<code class="hljs css has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">$<span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.ajax</span>(<span class="hljs-rules" style="box-sizing: border-box;">{ <span class="hljs-rule" style="box-sizing: border-box;"><span class="hljs-attribute" style="box-sizing: border-box;">type</span>:<span class="hljs-value" style="box-sizing: border-box; color: rgb(0, 102, 102);"> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"POST"</span>, url: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"some.php"</span>, data: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"name=John&location=Boston"</span>, success: <span class="hljs-function" style="box-sizing: border-box;">function(msg)</span>{ <span class="hljs-function" style="box-sizing: border-box;">alert( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Data Saved: "</span> + msg )</span></span></span>; <span class="hljs-rule" style="box-sizing: border-box;">}</span></span> });</code>