/*
js中XMLHttpRequest是什么,和ajax的关系,和promise的关系?
XMLHttpRequest(XHR)是浏览器提供的一个js API,用于在后台与服务器交换数据,无需刷新整个页面
XHR的核心特点:
1.异步通信:不阻塞页面渲染
2.局部更新:只更新部分页面内容
3.跨协议:支持http、https等
4.多种数据格式:json、xml、文本等
XHR和Ajax的关系
Ajax是一种技术方案/编程模式,而XHR是实现Ajax的一种工具。
XHR与Promise的关系
XHR使用回调函数处理异步结果,容易产生回调地狱。
解决方案:Promise 封装,将XHR封装成 Promise,使代码更优雅
发展历程
2005年:XMLHttpRequest(浏览器原生API)
2006年:jQuery.ajax (封装XHR)
2015年:Fetch浏览器原生API(使用了Promise)
2016年:Axios(第三方库,基于XHR/Fetch)
Promise是ES6引入的js语言特性
Fetch API是浏览器提供的原生Web API,用于发起网络请求,返回的是Promise对象。Fetch使用Promise来处理异步操作
*/
//创建XHR对象
const xhr = new XMLHttpRequest()
//配置请求,方法,url,是否异步
xhr.open('GET','https://XXXX',true)
//设置请求头(可选)
xhr.setRequestHeader('Content-Type','application/json')
//监听状态变化
xhr.onreadystatechange = function() {
//readyState 4表示请求完成,0未初始化,1已调用open,2已调用send,3正在接收数据
if(xhr.readyState === 4) {
if(xhr.statue === 200) { //http状态码200表示成功
console.log('成功:',xhr.responseText)
}else {
console.log('失败:',xhr.responseText)
}
}
}
xhr.send()//发送请求
//----------场景1,发送Get请求---------
function ajaxGet(url, callback) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
callback(null, JSON.parse(xhr.responseText));
} else if (xhr.readyState === 4) {
callback(new Error('请求失败'), null);
}
};
xhr.send();
}
// 使用
ajaxGet('https://api.example.com/users', (err, data) => {
if (err) {
console.error(err);
} else {
console.log(data);
}
});
//----------场景2,发送Post请求---------
function ajaxPost(url, data, callback) {
const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
callback(null, JSON.parse(xhr.responseText));
} else if (xhr.readyState === 4) {
callback(new Error('请求失败'), null);
}
};
xhr.send(JSON.stringify(data));
}
// 使用
ajaxPost('https://api.example.com/users',
{ name: '张三', age: 25 },
(err, data) => {
if (err) {
console.error(err);
} else {
console.log('创建成功:', data);
}
}
);
// ----------场景3, 回调地狱示例---------
ajaxGet('/api/user', (err1, user) => {
if (err1) return console.error(err1);
ajaxGet(`/api/posts/${user.id}`, (err2, posts) => {
if (err2) return console.error(err2);
ajaxGet(`/api/comments/${posts[0].id}`, (err3, comments) => {
if (err3) return console.error(err3);
console.log(comments);
// 嵌套太深,难以维护!
});
});
});
// ----------场景4,用Promise 封装解决回调地狱的问题---------
function ajax(url, options = {}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
const method = options.method || 'GET';
const data = options.data || null;
xhr.open(method, url, true);
// 设置请求头
if (options.headers) {
Object.keys(options.headers).forEach(key => {
xhr.setRequestHeader(key, options.headers[key]);
});
}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response = JSON.parse(xhr.responseText);
resolve(response);
} catch (e) {
resolve(xhr.responseText);
}
} else {
reject(new Error(`请求失败: ${xhr.status}`));
}
}
};
// 超时处理
if (options.timeout) {
xhr.timeout = options.timeout;
xhr.ontimeout = () => reject(new Error('请求超时'));
}
// 错误处理
xhr.onerror = () => reject(new Error('网络错误'));
// 发送请求
if (data && method === 'POST') {
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
} else {
xhr.send();
}
});
}
//使用 Promise 链式调用
ajax('/api/user')
.then(user => ajax(`/api/posts/${user.id}`))
.then(posts => ajax(`/api/comments/${posts[0].id}`))
.then(comments => console.log(comments))
.catch(err => console.error(err));
//使用 async/await(更优雅)
async function fetchData() {
try {
const user = await ajax('/api/user');
const posts = await ajax(`/api/posts/${user.id}`);
const comments = await ajax(`/api/comments/${posts[0].id}`);
console.log(comments);
} catch (err) {
console.error(err);
}
}
console