入门AJAX——XMLHttpRequest(Get)

article/2025/6/11 9:11:45

一、什么是 AJAX

AJAX = Asynchronous JavaScript And XML(异步的 JavaScript 和 XML)。

1、XML与异步JS

XML: 是一种比较老的前后端数据传输格式(已经几乎被 JSON 代替)。它的格式与HTML类似,通过严格的闭合自定义标签实现对数据的解释。

异步JS: 所谓异步与同步相对。同步指的是当JS遇到耗时操作(网络请求)时原地等待操作完成而阻塞下面的代码。而异步JS在遇到耗时操作时会继续执行下面的代码,等响应返回后继续处理。

2、AJAX的特点

AJAX最大的优点就是可以在不重新加载这个页面的情况下,与服务器交换部分数据并且更新部分网页内容。

3、本文我们会做什么

实现AJAX的方法可以大概分为两种:XMLHttpRequestfetch ,在本文,我们着重介绍前者。

既然是网络请求,就自然需要后端的支持。我们会首先搭建一个本地的后端服务器。前端小伙伴看到这可能不淡定了:

什么?让我去写后端,还是算了,告辞!

先别急着走嘛,当然啦,我这边已经把接口部署到服务器上了,大家如果嫌麻烦的话,下文中的所有 url 前缀请使用 http://39.105.227.198:1234并跳过下文中的后端接口搭建内容。

完整代码在文章末尾(前端,使用在线接口)

4、前置知识

学习本文之前,请确保你已经了解了下面知识点的相关概念和基础用法:

  • 基础的 dom 操作
  • 网络的基本知识(请求方法、请求传参、状态码等)
  • 了解在浏览器中调试的基本方法
  • 有对公共代码进行封装的意识

二、实现简单的 AJAX

1、基于express快速搭建后端接口

后端搭建不是本文重点,所以直接上代码,如果你使用的是服务器上的接口,可以跳过本节:

npm install express body-parser cookie-parser multer cors --save

根目录下新建 app.js

const express = require('express')
const cors = require('cors')
const app = express()app.use(cors())app.get('/test/1', (req, res) => {res.send('hello world')
})app.listen(1234, () => {console.log('服务器运行在 http://localhost:1234')
})

启动本服务器,我们将与 1234 端口交互:

node ./app.js
服务器运行在 http://localhost:1234

看到服务器运行在 http://localhost:1234标标标明服务器启动成功。

2、前端请求

下面我们通过代码来认识如何去使用 XMLHttpRequest发起AJAX请求:

// html 文件
<div id="app"></div><script>// 创建请求对象const xhr = new XMLHttpRequest()  // 如果你使用的是我提供的服务器接口,请将 url 修改为:// http://39.105.227.198:1234/test/1const url = 'http://localhost:1234/test/1'// 配置:向 url 发起异步 GET 请求xhr.open('GET', url, true)  xhr.onreadystatechange = function () {// 如果请求成功if (xhr.readyState === 4 && xhr.status === 200) {const res = xhr.responseText// 将 ID 为 app 的元素内文字改为响应的文字document.querySelector('#app').innerHTML = res}}// 发送请求xhr.send()
</script>

运行上面的 html 代码,你将在页面上看到后端返回的 hello world!,并在调试台看到网页发送了一次 GET 请求。

在这里插入图片描述
恭喜你,已经成功发出了一个 AJAX 请求并收到返回的结果!

3、知识点讲解

现在回看我们的代码都干了什么:

首先我们创建了一个请求对象 xhr :

const xhr = new XMLHttpRequest()

接下来我们对 AJAX 请求的控制本质上就是对这个 xhr 的控制。

然后我们对本次发送的请求进行配置:

// 如果你使用的是我提供的服务器接口,请将 url 修改为:
// http://39.105.227.198:1234/test/1
const url = 'http://39.105.227.198:1234/test/1'
// 配置:向 url 发起异步 GET 请求
xhr.open('GET', url, true)  

xhr.open()方法接收三个参数:method、url 和 isAsync

  • method: 本次请求的方法,如 get、post等。
  • url: 顾名思义,本次请求要发到哪里。
  • isAsync: 自己起的名字,本次请求是否异步,我们建议使用异步。

在 xhr 对象上有一个属性 readyState,该属性的取值范围是0~4,用于跟踪请求的进度并处理响应。

状态码常量描述
0UNSENTXHR 对象已创建,但尚未调用 open() 方法。
1OPENED已调用 open() 方法,请求已初始化,但尚未发送(未调用 send())。
2HEADERS_RECEIVED已调用 send() 方法,服务器已接收请求并返回响应头。
3LOADING服务器正在返回响应体(数据正在传输中),responseText 已有部分数据。
4DONE请求已完成(成功或失败),响应数据已完全接收。

onreadystatechange 是一个事件处理函数,当 XHR 的 readyState 状态发生变化时会触发该事件。开发者可以通过监听这个事件来跟踪请求的进度并处理响应。

xhr.onreadystatechange = function () {// 如果请求成功// status 是状态码,200 ~ 299 表示请求成功if (xhr.readyState === 4 && xhr.status === 200) {const res = xhr.responseText// 将 ID 为 app 的元素内文字改为响应的文字document.querySelector('#app').innerHTML = res}
}

所以上面代码的意思就是:当请求完成并且成功返回后,将 id 为 app 的元素内文字改为响应的结果(hello world)。然后我们使用 xhr.send()发送请求。

三、实现一个简单的搜索词推荐功能

让我们实现一个简单的搜索词推荐功能:页面上有一个输入框,只能接收一个小写英文字母,每次我们输入,都会主动向服务器发送当前输入框内的字母,然后服务器返回一个以这个字母开头的单词,前端将这个单词显示在页面上,如果没有匹配到任何一个单词,则返回 no suggest。

1、后端代码

如果你依旧使用我提供的接口,那么该节内容你依旧不需要阅读,记得请求时把 URL 改正确就行。

我们的代码基于之前的代码:

// app.js
const express = require('express')
const cors = require('cors')
const app = express()app.use(cors())app.get('/test/1', (req, res) => {res.send('hello world')
})
/* --------------添加代码-----------------*/
app.get('/test/2', (req, res) => {const char = req.query.charres.send(char2Word.get(char) || 'no suggest')
})const char2Word = new Map()char2Word.set('a', 'Anna')
char2Word.set('b', 'Brittany')
char2Word.set('c', 'Cinderella')
char2Word.set('d', 'Diana')
char2Word.set('e', 'Eva')
char2Word.set('f', 'Fiona')
char2Word.set('g', 'Gunda')
char2Word.set('h', 'Hege')
char2Word.set('i', 'Inga')
char2Word.set('j', 'Johanna')
char2Word.set('k', 'Kitty')
char2Word.set('l', 'Linda')
char2Word.set('m', 'Mom')
char2Word.set('n', 'No')
char2Word.set('o', 'Ok')
char2Word.set('p', 'Picture')
char2Word.set('q', 'Quick')
char2Word.set('r', 'Reset')
char2Word.set('s', 'String')
char2Word.set('t', 'TypeSrcipt')
char2Word.set('u', 'unit')
char2Word.set('v', 'Vicky')
char2Word.set('w', 'Wenche')
char2Word.set('x', 'x-rian')
char2Word.set('y', 'Yellow')
char2Word.set('z', 'Zoom')
/* --------------添加代码-----------------*/
app.listen(1234, () => {console.log('服务器运行在 http://localhost:1234')
})

2、前端代码

创建一个输入框和一个用于显示搜索结果的盒子:

<input id="charInput" placeholder="请输入一个小写字母" type="text"><div id="suggest">no suggest</div>

接下来,我们将请求进行简单的封装,以后我们想发起请求只需调用该函数:

function getRequest (url, callback) {const xhr = new XMLHttpRequest()xhr.open('GET', url, true)xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {const res = xhr.responseTextcallback(res)}}xhr.send()
}

然后给 input 输入框绑定输出事件回调,每次输入就调用getRequest将出入的字母发送到后端,获取到结果后将其设置到下面的 div 中:

inputChange = (str) => {// 如果你使用的是我提供的服务器接口,请将 url 修改为:// http://39.105.227.198:1234/test/2?char=${str}getRequest(`http://localhost:1234/test/2?char=${str}`, (res) => {document.querySelector('#suggest').innerHTML = res})
}document.querySelector('#charInput')
.addEventListener('input', (e) => inputChange(e.target.value))

至此前端代码书写完毕,运行 html ,在输入框中输入一个小写字母,发现下面的建议文字会跟着变化,且建议文字的首字母就是你输入的字母:

在这里插入图片描述

四、请求的超时取消

很多时候我们希望当请求长时间没有响应时取消该请求,在XMLHttpRequest中,我们使用 abort()函数实现。

const xhr = new XMLHttpRequest()
// ... 代码
xhr.abort()  // 取消请求

我们现在对上文中的 getRequest 函数进行以下扩展,使它支持超时取消:

// 添加超时事件和取消回调
function getRequest (url, callback, timeout = 5000, abortCallBack = () => {}) {const xhr = new XMLHttpRequest()setTimeout(() => {xhr.abort()abortCallBack()}, timeout)xhr.open('GET', url, true)xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {const res = xhr.responseTextcallback(res)}}xhr.send()
}

我们新建一个接口,让这个接口延迟3秒后返回结果。

然后布置两个盒子,其中一个设置为1秒超时,一个设置为5秒超时。

如果成功接收到接口的返回值,就将盒子的内容更改为该返回值,被取消请求的盒子内容改为:“我的请求被取消”。

让我们先预测一下,应该是第一个盒子的内容应该是“我的内容被取消”,因为它设置到超时时间短于结果的返回所需时间;而第二个盒子的内容可以被正常修改:

// app.js
.... 之前的代码
app.get('/test/3', (req, res) => {setTimeout(() => {res.send('成功返回')}, 3000)  // 延迟三秒返回,使其中一个盒子请求被取消
})
// html
<div class="box" id="abortable1">我的请求1秒后被取消</div>
<div class="box" id="abortable2">我的请求5秒后被取消</div><script>
function getRequest (url, callback, timeout = 5000, abortCallBack = () => {}) {const xhr = new XMLHttpRequest()setTimeout(() => {xhr.abort()abortCallBack()}, timeout)xhr.open('GET', url, true)xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {const res = xhr.responseTextcallback(res)}}xhr.send()
}// 超时时间设置为 1 秒,该元素的请求将由于超时被取消
getRequest('http://39.105.227.198:1234/test/3', (res) => {document.querySelector('#abortable1').innerHTML = res
}, 1000, () => {document.querySelector('#abortable1').innerHTML = '我的请求被取消'
})// 超时事件为 5 秒,将被正常修改
getRequest('http://39.105.227.198:1234/test/3', (res) => {document.querySelector('#abortable2').innerHTML = res
})
</script>

运行结果如图:
在这里插入图片描述
可以看到第一个元素的请求由于超时被取消,第二个元素正确返回并修改了文字。

五、完整代码

以下代码集成了本文章的三个例子,并对请求进行了简单的封装,可以直接运行:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.box {background: pink;width: 300px;height: 30px;line-height: 30px;margin: 10px 0;}</style>
</head>
<body><div id="app"></div><input id="charInput" placeholder="请输入一个小写字母" type="text"><div id="suggest">no suggest</div><div class="box" id="abortable1">我的请求1秒后被取消</div><div class="box" id="abortable2">我的请求5秒后被取消</div><script>function getRequest (url, callback, timeout = 5000, abortCallBack = () => {}) {const xhr = new XMLHttpRequest()setTimeout(() => {xhr.abort()abortCallBack()}, timeout)xhr.open('GET', url, true)xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {const res = xhr.responseTextcallback(res)}}xhr.send()}inputChange = (str) => {getRequest(`http://39.105.227.198:1234/test/2?char=${str}`, (res) => {document.querySelector('#suggest').innerHTML = res})}document.querySelector('#charInput').addEventListener('input', (e) => inputChange(e.target.value))getRequest('http://39.105.227.198:1234/test/1', (res) => {document.querySelector('#app').innerHTML = res})getRequest('http://39.105.227.198:1234/test/3', (res) => {document.querySelector('#abortable1').innerHTML = res}, 1000, () => {document.querySelector('#abortable1').innerHTML = '我的请求被取消'})getRequest('http://39.105.227.198:1234/test/3', (res) => {document.querySelector('#abortable2').innerHTML = res})</script>
</body>
</html>

http://www.hkcw.cn/article/quUDIaoZQK.shtml

相关文章

MDP的observations部分

文章目录 1.isaaclab的observations1.1 根状态相关观测base_pos_zbase_lin_vel &#xff08;use&#xff09;base_ang_vel &#xff08;use&#xff09;projected_gravity (use)root_pos_wroot_quat_wroot_lin_vel_wroot_ang_vel_w 1.2 关节状态相关观测joint_posjoint_pos_rel…

Rhino插件大全下载指南:解锁犀牛潜能,提升设计效率

Rhinoceros&#xff08;简称Rhino&#xff0c;犀牛&#xff09;以其强大的NURBS曲面建模能力、灵活的脚本环境以及与Grasshopper参数化设计工具的无缝集成&#xff0c;在全球工业设计、建筑设计、珠宝设计、船舶设计等领域备受推崇。为了进一步拓展Rhino的功能&#xff0c;满足…

百万级临床试验数据库TrialPanorama发布!AI助力新药研发与临床评价迎来新基石

2025年5月22日&#xff0c;伊利诺伊大学厄巴纳-香槟分校的研究团队在《arXiv》上发表了一篇前瞻性研究论文《TrialPanorama: Database and Benchmark for Systematic Review and Design of Clinical Trials》&#xff0c;该研究建立了一个临床试验数据库TrialPanorama&#xff…

运维 vm 虚拟机ip设置

虚拟网络设置 nat 模式 网卡 主机设置网卡地址 虚拟机绑定网卡

问题七、isaacsim中添加IMU传感器

0 前言 NVIDIA Isaac Sim 中的 IMU 传感器可跟踪车身运动并输出模拟加速度计和陀螺仪读数。与真实 IMU 传感器一样,模拟 IMU 可通过平台单元提供局部 x、y、z 轴的加速度和角速度测量值。 1 创建IMU传感器 按照下述步骤依次点击 使用python创建 基于IsaacSensorCreateImuSe…

AutoGenTestCase - 借助AI大模型生成测试用例

想象一下&#xff0c;你正在为一个复杂的支付系统编写测试用例&#xff0c;需求文档堆积如山&#xff0c;边缘场景层出不穷&#xff0c;手动编写让你焦头烂额。现在&#xff0c;有了AutoGenTestCase&#xff0c;这个AI驱动的“测试用例生成机”可以从需求文档中自动生成数百个测…

警惕假冒 CAPTCHA 攻击通过多阶段payload链部署远控和盗窃信息

在过去几个月中&#xff0c;Trend Micro 托管检测与响应&#xff08;MDR&#xff09;调查中发现假冒 CAPTCHA 的案例激增。这些 CAPTCHA 通过钓鱼邮件、URL 重定向、恶意广告或 SEO 污染投放。所有观察到的案例均表现出类似行为&#xff1a;指导用户将恶意命令复制粘贴到 Windo…

2024-2025-2-《移动机器人设计与实践》-复习资料-8……

2024-2025-2-《移动机器人设计与实践》-复习资料-1-7-CSDN博客 08 移动机器人基础编程 单选题&#xff08;6题&#xff09; 在ROS中&#xff0c;用于移动机器人速度控制的消息类型通常是&#xff1f; A. std_msgs/StringB. geometry_msgs/TwistC. sensor_msgs/ImageD. nav_ms…

楼宇自控系统赋能设备管理智能化集中化,驱动建筑节能高效运行

在建筑行业追求可持续发展与高效运营的当下&#xff0c;传统建筑设备管理模式因信息分散、调控粗放等问题&#xff0c;导致能源浪费严重、设备维护成本高企。而楼宇自控系统凭借对建筑内各类设备的智能化、集中化管理能力&#xff0c;成为解决这些难题的关键。通过实时监测、智…

三、kafka消费的全流程

五、多线程安全问题 1、多线程安全的定义 使用多线程访问一个资源&#xff0c;这个资源始终都能表现出正确的行为。 不被运行的环境影响、多线程可以交替访问、不需要任何额外的同步和协同。 2、Java实现多线程安全生产者 这里只是模拟多线程环境下使用生产者发送消息&…

集合类基础概念

目录 集合类概述 集合框架的体系结构 单列集合&#xff08;Collection&#xff09; List接口 Set接口 双列集合&#xff08;Map&#xff09; Map接口 线程安全与性能考虑 集合与数组的区别 大小是否固定 数据类型与存储 操作方法丰富性 内存与性能 类型安全与泛型…

1500多个免费的HTML模板

1500多个免费的HTML模板 用于网站&#xff0c;着陆页&#xff0c;博客&#xff0c;投资组合&#xff0c;电子商务和管理仪表板 Free HTML Website Templates on HTMLrev https://htmlrev.com/

博客操作规范

一、博客内容规范 专有名词&#xff1a;深蓝粗体&#xff0c;一级专有名词。 专有名词&#xff1a;靛蓝粗体&#xff0c;二级专有名词。 一般名词&#xff1a;浅蓝粗体&#xff0c;一般名词。 标记名词&#xff0c;蓝色粗体&#xff0c;标记性的名词。 重点句子&#xff1…

秋招Day12 - 计算机网络 - IP

IP协议的定义和作用&#xff1f; IP协议用于在计算机网络中传递数据包&#xff0c;定义了数据包的格式和处理规则&#xff0c;确保数据能够从一个设备传递到另一个设备&#xff0c;中间可能经过多个不同的设备&#xff08;路由器&#xff09;。 IP协议有哪些作用&#xff1f;…

电阻电容的选型

一、电阻选型 1.1安装方式 贴片电阻体积小&#xff0c;适用于SMT生产&#xff1b;功率小&#xff1b;易拆解插件电阻体积大&#xff1b;功率大&#xff1b;不易脱落 1.2阻值 电阻的阻值是离散的&#xff0c;其标称阻值根据精度分为E6、E12、E24、E48、E96、E192六大系列&am…

【网络安全】SRC漏洞挖掘思路/手法分享

文章目录 Tip1Tip2Tip3Tip4Tip5Tip6Tip7Tip8Tip9Tip10Tip11Tip12Tip13Tip14Tip15Tip16Tip17Tip18Tip19Tip20Tip21Tip22Tip23Tip24Tip25Tip26Tip27Tip28Tip29Tip30Tip1 “复制该主机所有 URL”:包含该主机上的所有接口等资源。 “复制此主机里的链接”:包括该主机加载的第三…

论文中pdf图片文件太大怎么办

文章目录 1.使用pdf文件的打印功能将文件导出2.操作3.前后文件大小对比 1.使用pdf文件的打印功能将文件导出 该方法在保证清晰度的同时&#xff0c;内存空间也能实现减少&#xff08;如果使用线上的压缩pdf工具&#xff0c;清晰度会直线下降&#xff09; 2.操作 点击文件—&…

力扣刷题 -- 232. 用栈实现队列

1. 题目 2. 思路分析 1&#xff09;创建两个栈空间&#xff0c;PushST&#xff0c;PopST&#xff1b; 2&#xff09;插入数据往PushST插&#xff0c;判断PopST是否为空&#xff0c;如果为空直接往PopST出数据&#xff1b;如PopST不为空&#xff0c;就先把PopST的数据先出栈&a…

结构型设计模式之Decorator(装饰器)

结构型设计模式之Decorator&#xff08;装饰器&#xff09; 前言&#xff1a; 本案例通过李四举例&#xff0c;不改变源代码的情况下 对“才艺”进行增强。 摘要&#xff1a; 摘要&#xff1a; 装饰器模式是一种结构型设计模式&#xff0c;允许动态地为对象添加功能而不改变其…

完美解决在pycharm中创建Django项目安装mysqlclient报错的问题(windows下)

正常情况下&#xff0c;在Windows安装mysqlclient会报错&#xff1a; 我这里用的是anaconda虚拟环境&#xff0c;安装前必须激活anacoda虚拟环境&#xff0c; 怎么激活虚拟环境&#xff1f;可以参考超详细的pycharmanaconda搭建python虚拟环境_pycharm anaconda环境搭建-CSDN博…