本文大部分摘抄自菜鸟教程,仅作学习使用。
AJAX简介
- AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
- AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
- AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
- AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
ajax使用
ajax基本使用
ajax基本使用分为四步:
创建XMLHttpRequest对象
XMLHttpRequest 用于在后台与服务器交换数据。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。 所有现代浏览器都支持XMLHttpRequest对象。
var XHR = new XMLHttpRequest();
向服务器发送请求
如需将请求发送到服务器,需使用 XMLHttpRequest 对象的 open() 和 send() 方法:
XHR.open("GET","ajax_info.txt",true);
XHR.send();
方法 | 作用 |
---|---|
open(method,url,async) | 规定请求的类型、URL 以及是否异步处理请求。 method:请求的类型;GET 或 POST url:文件在服务器上的位置 async:true(异步)或 false(同步) |
send(string) | 将请求发送到服务器。 string:仅用于 POST 请求 |
get和post的选择
与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。
然而,在以下情况中,请使用 POST 请求:
- 不愿使用缓存文件(更新服务器上的文件或数据库)
- 向服务器发送大量数据(POST 没有数据量限制)
- 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
获取服务器响应
如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性。
属性 | 描述 |
---|---|
responseText | 获得字符串形式的响应数据。 |
responseXML | 获得 XML 形式的响应数据。 |
您可以将获取的数据写入html:
document.querySelector(".box").innerText = XHR.responseText;
onreadystatechange 事件
当请求被发送到服务器时,我们需要执行一些基于响应的任务。
每当 readyState 改变时,就会触发 onreadystatechange 事件。
readyState 属性存有 XMLHttpRequest 的状态信息。
下面是 XMLHttpRequest 对象的三个重要的属性:
属性 | 描述 |
---|---|
onreadystatechange | 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。 |
readyState | 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。 0: 请求未初始化 1: 服务器连接已建立 2: 请求已接收 3: 请求处理中 4: 请求已完成,且响应已就绪 |
status | 200: "OK" 404: 未找到页面 |
在 onreadystatechange 事件中,我们规定当服务器响应已做好被处理的准备时所执行的任务。
当 readyState 等于 4 且 status 为 200 时,表示响应已就绪;
我们可以将第三步的代码
document.querySelector(".box").innerText = XHR.responseText;
改一下:
const box = document.querySelector(".box");
XHR.onreadystatechange=function()
{
if (XHR.readyState==4 && XHR.status==200)
{
box.innerText = XHR.responseText;
}
}
注意: onreadystatechange 事件被触发 4 次(0 - 4), 分别是: 0-1、1-2、2-3、3-4,对应着 readyState 的每个变化。
到此基本的ajax已完成!
使用回调函数
回调函数是一种以参数形式传递给另一个函数的函数。
如果您的网站上存在多个 AJAX 任务,那么您应该为创建 XMLHttpRequest 对象编写一个标准的函数,并为每个 AJAX 任务调用该函数。
该函数调用应该包含 URL 以及发生 onreadystatechange 事件时执行的任务(例子来自菜鸟教程):
<!DOCTYPE html>
<html>
<head>
<script>
var xmlhttp;
function loadXMLDoc(url,cfunc){
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}
else{// IE6, IE5 代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=cfunc;
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
function myFunction(){
loadXMLDoc("https://www.runoob.com/try/ajax/ajax_info.txt",function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
});
}
</script>
</head>
<body>
<div id="myDiv"><h2>使用 AJAX 修改文本内容</h2></div>
<button type="button" onclick="myFunction()">修改内容</button>
</body>
</html>
ASP/PHP
即在调用open()
函数的时候,传入的url
参数后面加上?q=
,再加个变量:
str = 'a';
xmlhttp.open("GET",'gethint.php?q='+str,true);
AJAX 可用来与数据库进行动态通信
其实就是通过PHP文件与数据库进行交互。
使用 AJAX 来读取来自 XML 文件的信息
菜鸟教程上的例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
table,th,td {
border : 1px solid black;
border-collapse: collapse;
}
th,td {
padding: 5px;
}
</style>
</head>
<body>
<h1>XMLHttpRequest 对象</h1>
<button type="button" onclick="loadXMLDoc()">获取我收藏的 CD</button>
<table id="demo"></table>
<script>
function loadXMLDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xhttp.open("GET", "cd_catalog.xml", true);
xhttp.send();
}
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<tr><th>Artist</th><th>Title</th></tr>";
var x = xmlDoc.getElementsByTagName("CD");
for (i = 0; i <x.length; i++) {
table += "<tr><td>" +
x[i].getElementsByTagName("ARTIST")[0].childNodes[0].nodeValue +
"</td><td>" +
x[i].getElementsByTagName("TITLE")[0].childNodes[0].nodeValue +
"</td></tr>";
}
document.getElementById("demo").innerHTML = table;
}
</script>
</body>
</html>
Fetch API
fetch()
是 XMLHttpRequest
的升级版,用于在 JavaScript
脚本里面发出 HTTP 请求。
浏览器原生提供这个对象。
基本用法
fetch()的功能与 XMLHttpRequest 基本相同,但有三个主要的差异:
1、fetch()
使用 Promise,不使用回调函数,因此大大简化了写法,写起来更简洁。
2、fetch()
采用模块化设计,API 分散在多个对象上(Response 对象
、Request 对象
、Headers 对象
),更合理一些;相比之下,XMLHttpRequest
的 API 设计并不是很好,输入、输出、状态都在同一个接口管理,容易写出非常混乱的代码。
3、fetch()
通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHttpRequest 对象不支持数据流,所有的数据必须放在缓存里,不支持分块读取,必须等待全部拿到后,再一次性吐出来。
在用法上,fetch()接受一个 URL 字符串作为参数,默认向该网址发出 GET 请求,返回一个 Promise 对象。
fetch(url)
.then(...)
.catch(...)
例子,从服务器获取json:
fetch('https://api.github.com/users/can-dy-jack')
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Request Failed', error));
fetch()
接收到的response
是一个 Stream 对象
,response.json()
是一个异步操作
,取出所有内容,并将其转为 JSON 对象。
注:Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
Promise 可以使用 await 语法改写,使得语义更清晰。
async function getJSON() {
let url = 'https://api.github.com/users/ruanyf';
try {
let response = await fetch(url);
return await response.json();
} catch (error) {
console.log('Request Failed', error);
}
}
console.log(getJSON()); // 调用getJSON(),并输出获取到的Promise
await语句必须放在try...catch里面,这样才能捕捉异步操作中可能发生的错误。
Response 对象
Response 对象:处理 HTTP 回应。
Response 对象的同步属性
fetch()请求成功以后,得到的是一个 Response 对象。它对应服务器的 HTTP 回应。
Response
包含的数据通过 Stream 接口异步读取,但是它还包含一些同步属性,对应 HTTP 回应的标头信息(Headers),可以立即读取。
示例:
async function fetchText() {
let response = await fetch('/readme.txt');
console.log(response.status);
console.log(response.statusText);
}
response.status
和response.statusText
就是 Response
的同步属性,可以立即读取。
标头信息属性有下面这些(more: MDN-API/Response | Response 对象):
- Response.ok
- Response.statusText
- Response.status
- Response.url
- Response.type
- ... ...
判断请求是否成功
fetch()发出请求以后,只有网络错误,或者无法连接时,fetch()才会报错,其他情况都不会报错,而是认为请求成功。
这就是说,即使服务器返回的状态码是 4xx
或 5xx
,fetch()也不会报错(即 Promise 不会变为 rejected状态
)。
只有通过Response.status
属性,得到 HTTP 回应的真实状态码,才能判断请求是否成功。
async function fetchText() {
let response = await fetch('https://api.github.com/users/can-dy-jack');
if (response.status >= 200 && response.status < 300) {
return await response.text();
} else {
throw new Error(response.statusText);
}
}
另一种方法是判断Response.oK
是否为true。
Response.headers 属性
Response 对象还有一个Response.headers属性,指向一个 Headers 对象,对应 HTTP 回应的所有标头。
Headers 对象可以使用for...of
循环进行遍历。
async function test(){
const response = await fetch('https://api.github.com/users/ruanyf');
for (let [key, value] of response.headers) {
console.log(`${key} : ${value}`);
}
// 或者
/*
for (let [key, value] of response.headers.entries()) {
console.log(`${key} : ${value}`);
}
*/
}
test();
Headers 对象提供了以下方法,用来操作标头。
读取内容的方法
Response对象根据服务器返回的不同类型的数据,提供了不同的读取方法。
- response.text():得到文本字符串。
- response.json():得到 JSON 对象。
- response.blob():得到二进制 Blob 对象。
- response.formData():得到 FormData 表单对象。
- response.arrayBuffer():得到二进制 ArrayBuffer 对象。
上面5个读取方法都是异步的,返回的都是 Promise 对象。必须等到异步操作结束,才能得到服务器返回的完整数据。
Stream 对象只能读取一次,读取完就没了。这意味着,前一节的五个读取方法,只能使用一个,否则会报错。
Response 对象提供Response.clone()方法,创建Response对象的副本,实现多次读取。
Response.body 属性
Response.body
属性是 Response 对象暴露出的底层接口,返回一个 ReadableStream 对象
,供用户操作。
它可以用来分块读取内容,应用之一就是[显示下载的进度]。
fetch()的第二个参数:定制 HTTP 请求
fetch()的第一个参数是 URL,还可以接受第二个参数,作为配置对象,定制发出的 HTTP 请求。
fetch(url, optionObj)
HTTP 请求的方法、标头、数据体都在这个对象里面设置。
Post请求
const response = await fetch(url, {
method: 'POST',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
body: 'foo=bar&lorem=ipsum',
});
const json = await response.json();
提交json数据
const user = { name: 'John', surname: 'Smith' };
const response = await fetch('/article/fetch/post/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(user)
});
提交表单
const form = document.querySelector('form');
const response = await fetch('/users', {
method: 'POST',
body: new FormData(form)
})
文件上传
const input = document.querySelector('input[type="file"]');
const data = new FormData();
data.append('file', input.files[0]);
data.append('user', 'foo');
fetch('/avatars', {
method: 'POST',
body: data
});
直接上传二进制文件
let blob = await new Promise(resolve =>
canvasElem.toBlob(resolve, 'image/png')
);
let response = await fetch('/article/fetch/post/image', {
method: 'POST',
body: blob
});
fetch()第二个参数配置对象的完整 API
const response = fetch(url, {
method: "GET",
headers: {
"Content-Type": "text/plain;charset=UTF-8"
},
body: undefined,
referrer: "about:client",
referrerPolicy: "no-referrer-when-downgrade",
mode: "cors",
credentials: "same-origin",
cache: "default",
redirect: "follow",
integrity: "",
keepalive: false,
signal: undefined
});