一、XMLHttpRequest
1.XMLHttpRequest 对象定义
XMLHttpRequest(简称 XHR )是浏览器提供的 原生 API ,用于在客户端(浏览器)与服务器之间进行 异步数据交互 ,支持发送 HTTP/HTTPS 请求并接收响应,是实现 AJAX(异步 JavaScript 和 XML)的核心工具。通过 XHR,网页可以在不重新加载整个页面的情况下,更新局部内容(如加载数据、提交表单等)。
关系:axios 内部采用XMLHttpRequest 与服务器交互

2.核心功能
- 创建异步请求:无需刷新页面即可与服务器通信。
- 支持多种请求方法:GET、POST、PUT、DELETE 等。
- 处理响应数据:接收文本、JSON、XML 等格式的数据。
- 细粒度控制请求:设置请求头、超时时间、中断请求等。
⑴.关键属性
属性名 | 描述 |
---|---|
readyState |
请求状态 (数值,共 5 种状态): 0 (未初始化)、1 (已调用 open() )、2 (请求已发送)、3 (响应中)、4 (请求完成)。 |
status |
HTTP 状态码 (如 200 成功,404 未找到,500 服务器错误)。 |
statusText |
状态码对应的文本描述(如 OK 、Not Found )。 |
response |
响应内容(自动根据响应类型解析为 DOM、JSON、文本等)。 |
responseText |
文本格式的响应内容(常用,如 JSON 字符串)。 |
responseXML |
XML 格式的响应内容(解析为 DOM 对象)。 |
timeout |
请求超时时间(毫秒),超时触发 ontimeout 事件。 |
withCredentials |
是否携带跨域 Cookie(默认 false ,跨域时需设为 true )。 |
⑵.核心方法
方法名 | 语法 | 描述 |
---|---|---|
open() |
xhr.open(method, url, async) |
初始化请求: - method :请求方法(GET /POST 等) - url :目标 URL - async :是否异步(默认 true ,设 false 会阻塞主线程)。 |
send() |
xhr.send([body]) |
发送请求: - GET 请求:send() 无参数 - POST 请求:send(body) 可传入字符串、FormData、Blob 等。 |
setRequestHeader() |
xhr.setRequestHeader(name, value) |
设置请求头(需在 open() 之后、send() 之前调用)。 |
abort() |
xhr.abort() |
中断请求(触发 onabort 事件)。 |
getResponseHeader() |
xhr.getResponseHeader(name) |
获取指定响应头的值。 |
getAllResponseHeaders() |
xhr.getAllResponseHeaders() |
获取所有响应头(字符串形式)。 |
⑶.事件监听
通过监听事件处理请求的不同阶段,常用事件:
事件名 | 触发时机 | 示例代码 |
---|---|---|
onreadystatechange |
readyState 变化时触发(最通用,需结合 status 判断是否成功)。 |
javascript<br>xhr.onreadystatechange = () => {<br> if (xhr.readyState === 4 && xhr.status === 200) {<br> console.log(xhr.responseText);<br> }<br>};<br> |
onload |
请求成功完成时触发(替代 readyState === 4 的简化写法)。 |
javascript<br>xhr.addEventListener('load', () => {<br> if (xhr.status === 200) {<br> console.log(xhr.response);<br> }<br>});<br> |
onerror |
请求发生网络错误(如 DNS 失败、连接中断)时触发。 | javascript<br>xhr.addEventListener('error', () => {<br> console.error('请求失败');<br>});<br> |
ontimeout |
请求超过 timeout 时间时触发。 |
javascript<br>xhr.timeout = 5000; // 5 秒超时<br>xhr.ontimeout = () => {<br> console.error('请求超时');<br>};<br> |
onprogress |
接收数据时触发(可获取进度信息,如 event.loaded 、event.total )。 |
3.使用XMLHttpRequest
步骤:
创建 XMLHttpRequest 对象
通过 new
关键字实例化 XHR 对象:
const xhr = new XMLHttpRequest(); // 现代浏览器标准写法
// 旧版 IE(5/6)需使用 ActiveXObject(已淘汰):
// const xhr = new ActiveXObject("Microsoft.XMLHTTP");
配置请求方法和请求 url 地址
监听 loadend 事件,接收响应结果
发起请求

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest_基础使用</title>
</head>
<body>
<p class="my-p"></p>
<script>
/**
* 目标:使用XMLHttpRequest对象与服务器通信
* 1. 创建 XMLHttpRequest 对象
* 2. 配置请求方法和请求 url 地址
* 3. 监听 loadend 事件,接收响应结果
* 4. 发起请求
*/
// 1. 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest()
// 2. 配置请求方法和请求 url 地址
xhr.open('GET', 'http://hmajax.itheima.net/api/province')
// 3. 监听 loadend 事件,接收响应结果
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
const data = JSON.parse(xhr.response)
console.log(data.list.join('<br>'))
document.querySelector('.my-p').innerHTML = data.list.join('<br>')
})
// 4. 发起请求
xhr.send()
</script>
</body>
</html>

4.XMLHttpRequest - 查询参数

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest_查询参数</title>
</head>
<body>
<p class="city-p"></p>
<script>
/**
* 目标:使用XHR携带查询参数,展示某个省下属的城市列表
*/
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://hmajax.itheima.net/api/city?pname=辽宁省')
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
const data = JSON.parse(xhr.response)
console.log(data)
document.querySelector('.city-p').innerHTML = data.list.join('<br>')
})
xhr.send()
</script>
</body>
</html>

5.案例:地区查询

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>案例_地区查询</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<style>
:root {
font-size: 15px;
}
body {
padding-top: 15px;
}
</style>
</head>
<body>
<div class="container">
<form id="editForm" class="row">
<!-- 输入省份名字 -->
<div class="mb-3 col">
<label class="form-label">省份名字</label>
<input type="text" value="北京" name="province" class="form-control province" placeholder="请输入省份名称" />
</div>
<!-- 输入城市名字 -->
<div class="mb-3 col">
<label class="form-label">城市名字</label>
<input type="text" value="北京市" name="city" class="form-control city" placeholder="请输入城市名称" />
</div>
</form>
<button type="button" class="btn btn-primary sel-btn">查询</button>
<br><br>
<p>地区列表: </p>
<ul class="list-group">
<!-- 示例地区 -->
<li class="list-group-item">东城区</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/**
* 目标: 根据省份和城市名字, 查询对应的地区列表
*/
// 1. 查询按钮-点击事件
document.querySelector('.sel-btn').addEventListener('click', () => {
// 2. 收集省份和城市名字
const pname = document.querySelector('.province').value
const cname = document.querySelector('.city').value
// 3. 组织查询参数字符串
const qObj = {
pname,
cname
}
// 查询参数对象 -> 查询参数字符串
const paramsObj = new URLSearchParams(qObj)
const queryString = paramsObj.toString()
console.log(queryString)
// 4. 使用XHR对象,查询地区列表
const xhr = new XMLHttpRequest()
xhr.open('GET', `http://hmajax.itheima.net/api/area?${queryString}`)
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
const data = JSON.parse(xhr.response)
console.log(data)
const htmlStr = data.list.map(areaName => {
return `<li class="list-group-item">${areaName}</li>`
}).join('')
console.log(htmlStr)
document.querySelector('.list-group').innerHTML = htmlStr
})
xhr.send()
})
</script>
</body>
</html>

6.XMLHttpRequest - 数据提交

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMLHttpRequest_数据提交</title>
</head>
<body>
<button class="reg-btn">注册用户</button>
<script>
/**
* 目标:使用xhr进行数据提交-完成注册功能
*/
document.querySelector('.reg-btn').addEventListener('click', () => {
const xhr = new XMLHttpRequest()
xhr.open('POST', 'http://hmajax.itheima.net/api/register')
xhr.addEventListener('loadend', () => {
console.log(xhr.response)
})
// 设置请求头-告诉服务器内容类型(JSON字符串)
xhr.setRequestHeader('Content-Type', 'application/json')
// 准备提交的数据
const userObj = {
username: 'itheima0074444',
password: '7654321'
}
const userStr = JSON.stringify(userObj)
// 设置请求体,发起请求
xhr.send(userStr)
})
</script>
</body>
</html>

二、Promise
1.Promise 定义
Promise 是 ES6(ECMAScript 2015) 引入的 异步编程解决方案 ,用于表示一个异步操作的最终完成(或失败)状态及其结果值。它通过统一的接口规范处理异步操作,避免 "回调地狱",使代码更易读、可维护

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>认识Promise</title>
</head>
<body>
<script>
/**
* 目标:使用Promise管理异步任务
*/
// 1. 创建Promise对象
const p = new Promise((resolve, reject) => {
// 2. 执行异步代码
setTimeout(() => {
// resolve('模拟AJAX请求-成功结果')
reject(new Error('模拟AJAX请求-失败结果'))
}, 2000)
})
// 3. 获取结果
p.then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
</script>
</body>
</html>

2.Promise - 三种状态

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>认识Promise状态</title>
</head>
<body>
<script>
/**
* 目标:认识Promise状态
*/
// 1. 创建Promise对象(pending-待定状态)
const p = new Promise((resolve, reject) => {
// Promise对象创建时,这里的代码都会执行了
// 2. 执行异步代码
setTimeout(() => {
// resolve() => 'fulfilled状态-已兑现' => then()
resolve('模拟AJAX请求-成功结果')
// reject() => 'rejected状态-已拒绝' => catch()
reject(new Error('模拟AJAX请求-失败结果'))
}, 2000)
})
console.log(p)
// 3. 获取结果
p.then(result => {
console.log(result)
}).catch(error => {
console.log(error)
})
</script>
</body>
</html>

3.使用Promise + XHR 获取省份列表

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>案例_使用Promise+XHR_获取省份列表</title>
</head>
<body>
<p class="my-p"></p>
<script>
/**
* 目标:使用Promise管理XHR请求省份列表
* 1. 创建Promise对象
* 2. 执行XHR异步代码,获取省份列表
* 3. 关联成功或失败函数,做后续处理
*/
// 1. 创建Promise对象
const p = new Promise((resolve, reject) => {
// 2. 执行XHR异步代码,获取省份列表
const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://hmajax.itheima.net/api/province')
xhr.addEventListener('loadend', () => {
// xhr如何判断响应成功还是失败的?
// 2xx开头的都是成功响应状态码
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
xhr.send()
})
// 3. 关联成功或失败函数,做后续处理
p.then(result => {
console.log(result)
document.querySelector('.my-p').innerHTML = result.list.join('<br>')
}).catch(error => {
// 错误对象要用console.dir详细打印
console.dir(error)
// 服务器返回错误提示消息,插入到p标签显示
document.querySelector('.my-p').innerHTML = error.message
})
</script>
</body>
</html>

三、封装简易版axios
1.封装_简易axios_获取省份列表

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>封装_简易axios函数_获取省份列表</title>
</head>
<body>
<p class="my-p"></p>
<script>
/**
* 目标:封装_简易axios函数_获取省份列表
* 1. 定义myAxios函数,接收配置对象,返回Promise对象
* 2. 发起XHR请求,默认请求方法为GET
* 3. 调用成功/失败的处理程序
* 4. 使用myAxios函数,获取省份列表展示
*/
// 1. 定义myAxios函数,接收配置对象,返回Promise对象
function myAxios(config) {
return new Promise((resolve, reject) => {
// 2. 发起XHR请求,默认请求方法为GET
const xhr = new XMLHttpRequest()
xhr.open(config.method || 'GET', config.url)
xhr.addEventListener('loadend', () => {
// 3. 调用成功/失败的处理程序
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
xhr.send()
})
}
// 4. 使用myAxios函数,获取省份列表展示
myAxios({
url: 'http://hmajax.itheima.net/api/province'
}).then(result => {
console.log(result)
document.querySelector('.my-p').innerHTML = result.list.join('<br>')
}).catch(error => {
console.log(error)
document.querySelector('.my-p').innerHTML = error.message
})
</script>
</body>
</html>

2.封装_简易axios_获取地区列表

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>封装_简易axios函数_获取地区列表</title>
</head>
<body>
<p class="my-p"></p>
<script>
/**
* 目标:封装_简易axios函数_获取地区列表
* 1. 判断有params选项,携带查询参数
* 2. 使用URLSearchParams转换,并携带到url上
* 3. 使用myAxios函数,获取地区列表
*/
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
// 1. 判断有params选项,携带查询参数
if (config.params) {
// 2. 使用URLSearchParams转换,并携带到url上
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
// 把查询参数字符串,拼接在url?后面
config.url += `?${queryString}`
}
xhr.open(config.method || 'GET', config.url)
xhr.addEventListener('loadend', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
xhr.send()
})
}
// 3. 使用myAxios函数,获取地区列表
myAxios({
url: 'http://hmajax.itheima.net/api/area',
params: {
pname: '辽宁省',
cname: '大连市'
}
}).then(result => {
console.log(result)
document.querySelector('.my-p').innerHTML = result.list.join('<br>')
})
</script>
</body>
</html>

3.封装_简易axios_注册用户

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>封装_简易axios函数_注册用户</title>
</head>
<body>
<button class="reg-btn">注册用户</button>
<script>
/**
* 目标:封装_简易axios函数_注册用户
* 1. 判断有data选项,携带请求体
* 2. 转换数据类型,在send中发送
* 3. 使用myAxios函数,完成注册用户
*/
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
if (config.params) {
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
config.url += `?${queryString}`
}
xhr.open(config.method || 'GET', config.url)
xhr.addEventListener('loadend', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
} else {
reject(new Error(xhr.response))
}
})
// 1. 判断有data选项,携带请求体
if (config.data) {
// 2. 转换数据类型,在send中发送
const jsonStr = JSON.stringify(config.data)
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(jsonStr)
} else {
// 如果没有请求体数据,正常的发起请求
xhr.send()
}
})
}
document.querySelector('.reg-btn').addEventListener('click', () => {
// 3. 使用myAxios函数,完成注册用户
myAxios({
url: 'http://hmajax.itheima.net/api/register',
method: 'POST',
data: {
username: 'itheima999',
password: '666666'
}
}).then(result => {
console.log(result)
}).catch(error => {
console.dir(error)
})
})
</script>
</body>
</html>

四、案例:天气预报



代码详见第三code