AJAX 不是 JavaScript 的规范,而是用 JavaScript 执行异步网络请求,缩写为:Asynchronous JavaScript and XML
JavaScript 的一个重要的特性就是单线程执行模式
AJAX 请求是异步执行的,所以 JavaScript 通过 AJAX 回调函数获得响应
Web的运作原理:一次 HTTP 请求对应一个页面, 所以要想同一个界面请求不同数据,必须使用异步执行操作
在现代浏览器上写 AJAX 主要依靠XMLHttpRequest
对象:
function success(text) {
var textarea = document.getElementById('test-response-text');
textarea.value = text;
}
function fail(code) {
var textarea = document.getElementById('test-response-text');
textarea.value = 'Error code: ' + code;
}
var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象
request.onreadystatechange = function () { // 状态发生变化时,函数被回调
if (request.readyState === 4) { // 成功完成
// 判断响应结果:
if (request.status === 200) {
// 成功,通过responseText拿到响应的文本:
return success(request.responseText);
} else {
// 失败,根据响应码判断失败原因:
return fail(request.status);
}
} else {
// HTTP请求还在继续...
}
}
// 发送请求:
request.open('GET', '/api/categories');
request.send();
alert('请求已发送,请等待响应...');
解释:
XMLHttpRequest
对象的open()
方法有3个参数,第一个参数指定是GET
还是POST
,第二个参数指定URL
地址,第三个参数指定是否使用异步,默认是true
,所以不用写
注意,千万不要把第三个参数指定为false
,否则浏览器将停止响应,直到AJAX请求完成。如果这个请求耗时10
秒,那么10
秒内你会发现浏览器处于“假死”状态
最后调用send()
方法才真正发送请求。GET
请求不需要参数,POST
请求需要把body
部分以字符串或者FormData
对象传进去
安全限制
上面代码的URL使用的是相对路径。如果你把它改为'http://www.sina.com.cn/'
,再运行,肯定报错
是因为浏览器的同源策略导致的。默认情况下,JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致
完全一致的意思是,域名要相同(www.example.com和example.com不同)
,协议要相同(http和https不同)
,端口号要相同(默认是:80端口,它和:8080就不同)。有的浏览器口子松一点,允许端口不同,大多数浏览器都会严格遵守这个限制。
那怎么用JavaScript请求外域(就是其他网站)的URL?
方法一:
一是通过Flash插件发送HTTP请求,这种方式可以绕过浏览器的安全限制,但必须安装Flash,并且跟Flash交互。不过Flash用起来麻烦,而且现在用得也越来越少了
方法二:
二是通过在同源域名下架设一个代理服务器来转发,JavaScript负责把请求发送到代理服务器:
'/proxy?url=http://www.sina.com.cn'
代理服务器再把结果返回,这样就遵守了浏览器的同源策略。这种方式麻烦之处在于需要服务器端额外做开发。
方法三
第三种方式称为JSONP,它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源
JSONP一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了
<html>
<head>
<meta charset="utf-8" />
<title>学习JSONP</title>
<script src="http://example.com/abc.js"></script>
<script>
function refreshPrice(data) {
var p = document.getElementById('test-jsonp');
p.innerHTML = '当前价格:' +
data['0000001'].name +':' +
data['0000001'].price + ';' +
data['1399001'].name + ':' +
data['1399001'].price;
}
</script>
<script>
function getPrice() {
var js = document.createElement('script');
var head = document.getElementsByTagName('head')[0];
js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice';
head.appendChild(js);
}
</script>
</head>
<body>
<p id='test-jsonp'>当前价格:</p>
<button type="button" onclick="getPrice()">刷新</button>
</body>
</html>
解释:
- 方法
getPrice()
中 创建了一个script
元素 - 并给
script
元素 添加引用js.src
, 关键代码在src
中的callback=refreshPrice
- 给创建
head
便签,并将script
添加为子元素 - 通过
button
的点击事件,触发getPrice()
-
getPrice()
中的js.src
获取到回调方法refreshPrice()
并异步执行,并回调请求结果 -
refreshPrice()
方法获取到数据进行展示