JavaScript前后端交互-AJAX/fetch
摘自千峰教育kerwin的js教程
AJAX
1、AJAX 的优势
- 不需要插件的支持,原生 js 就可以使用
- 用户体验好(不需要刷新页面就可以更新数据)
- 减轻服务端和带宽的负担
- 缺点: 搜索引擎的支持度不够,因为数据都不在页面上,搜索引擎搜索不到
2、AJAX 的使用
- 在 js 中有内置的构造函数来创建 ajax 对象
- 创建 ajax 对象以后,我们就使用 ajax 对象的方法去发送请求和接受响应
3、AJAX发送请求
- 创建AJAX对象
- 配置连接信息(最好不要配置成同步)
- 发送
const xhr = new XMLHttpRequest();// xhr 对象中的 open 方法是来配置请求信息的
// 第一个参数是本次请求的请求方式 get / post / put / ...
// 第二个参数是本次请求的 url
// 第三个参数是本次请求是否异步,默认 true 表示异步,false 表示同步
// xhr.open('请求方式', '请求地址', 是否异步)
xhr.open('get', './data.php')// 使用 xhr 对象中的 send 方法来发送请求
xhr.send()
4、AJAX接收响应
- 发送完成后,我们就需要等待服务端的消息
- 如果服务端正常的话,响应也能回到客户端
- 但是我们拿不到响应
- 如果想拿到响应,我们有两个前提条件
- 本次 HTTP 请求是成功的,也就是我们之前说的 http 状态码为 200 ~ 299
- ajax 对象也有自己的状态码,用来表示本次 ajax 请求中各个阶段
4.1、AJAX状态码
- ajax 状态码 -
xhr.readyState - 是用来表示一个 ajax 请求的全部过程中的某一个状态
readyState === 0: 表示未初始化完成,也就是open方法还没有执行readyState === 1: 表示配置信息已经完成,也就是执行完open之后readyState === 2: 表示send方法已经执行完成readyState === 3: 表示正在解析响应内容readyState === 4: 表示响应内容已经解析完毕,可以在客户端使用了
- 这个时候我们就会发现,当一个 ajax 请求的全部过程中,只有当
readyState === 4的时候,我们才可以正常使用服务端给我们的数据 - 所以,配合 http 状态码为 200 ~ 299
- 一个 ajax 对象中有一个成员叫做
xhr.status - 这个成员就是记录本次请求的 http 状态码的
- 一个 ajax 对象中有一个成员叫做
- 两个条件都满足的时候,才是本次请求正常完成
4.2、readyStateChange事件
-
在 ajax 对象中有一个事件,叫做
readyStateChange事件 -
这个事件是专门用来监听 ajax 对象的
readyState值改变的的行为 -
也就是说只要
readyState的值发生变化了,那么就会触发该事件(所以响应过程会触发多次) -
所以我们就在这个事件中来监听 ajax 的
readyState是不是到 4 了const xhr = new XMLHttpRequest() xhr.open('get', './data.php')xhr.send()xhr.onreadyStateChange = function () {// 每次 readyState 改变的时候都会触发该事件// 我们就在这里判断 readyState 的值是不是到 4// 并且 http 的状态码是不是 200 ~ 299if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {// 这里表示验证通过// 我们就可以获取服务端给我们响应的内容了} }
4.3、onload事件
- 相比于上述事件,这个只有在
xhr.readyState === 4时才会触发xhr.onload = function () {if (xhr.status == 200) {} else of (xhr.status == 404) {} }
4.4、responseText响应体
-
ajax 对象中的
responseText成员 -
就是用来记录服务端给我们的响应体内容的
-
所以我们就用这个成员来获取响应体内容就可以
const xhr = new XMLHttpRequest() xhr.open('get', './data.php')xhr.send()xhr.onreadyStateChange = function () {if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {// 我们在这里直接打印 xhr.responseText 来查看服务端给我们返回的内容console.log(xhr.responseText)} }
5、发送post和get请求时如何携带参数
5.1、get请求携带参数
- get 请求的参数就直接在 url 后面进行拼接就可以
const xhr = new XMLHttpRequest() // 直接在地址后面加一个 ?,然后以 key=value 的形式传递 // 两个数据之间以 & 分割 xhr.open('get', './data.php?a=100&b=200')xhr.send()- 这样服务端就能接受到两个参数
- 一个是 a,值是 100
- 一个是 b,值是 200
5.2、 post请求携带参数
- post 请求的参数是携带在请求体中的,所以不需要再 url 后面拼接
const xhr = new XMLHttpRequest() xhr.open('get', './data.php')// 如果是用 ajax 对象发送 post 请求,必须要先设置一下请求头中的 content-type // 告诉一下服务端我给你的是一个什么样子的数据格式 xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')// 请求体直接再 send 的时候写在 () 里面就行 // 不需要问号,直接就是 'key=value&key=value' 的形式 xhr.send('a=100&b=200')application/x-www-form-urlencoded表示的数据格式就是key=value&key=value
6、封装AJAX
- 重点:要注意header和data的数据格式处理成对应的
function queryStringify(obj) {let str = ''for (let k in obj) str += `${k}=${obj[k]}&`return str.slice(0, -1)
}// 封装 ajax
function ajax(options) {let defaultoptions = {url: "",method: "GET",async: true,data: {},headers: {},success: function () { },error: function () { }}// 默认值合并,保证所有参数都有效let { url, method, async, data, headers, success, error } = {...defaultoptions,...options}// 当传的是对象,且设置header也是json时,将传的对象{key:value}转化为jsonif (typeof data === 'object' && headers["content-type"]?.indexOf("json") > -1) {data = JSON.stringify(data)}else {// 以下情况需要处理// 1. 传的是对象,但是header设置的xxx-form-urlencoded// 2. 传的直接就是表单(不设置的话默认是form编码) name=123&age=10data = queryStringify(data)}// 如果是 get 请求, 并且有参数, 那么直接组装一下 url 信息if (/^get$/i.test(method) && data) url += '?' + data// 4. 发送请求const xhr = new XMLHttpRequest()xhr.open(method, url, async)xhr.onload = function () {if (!/^2\d{2}$/.test(xhr.status)) {error(`错误状态码:${xhr.status}`)return }// 执行解析try {let result = JSON.parse(xhr.responseText)success(result)} catch (err) {error('解析失败 ! 因为后端返回的结果不是 json 格式字符串')}}// 设置请求头内的信息for (let k in headers) xhr.setRequestHeader(k, headers[k])if (/^get$/i.test(method)) {xhr.send()} else {xhr.send(data)}
}
ajax({url:"http://localhost:3000/users",method:"GET",async:true,// 这里header默认是form编码,但是传的对象,所以走else逻辑data:{username:"kerwin",password:"123"}, headers:{},success:function(res){console.log(res)},error:function(err){console.log(err)}
})
7、回调地狱
-
当一个回调函数嵌套一个回调函数的时候
-
就会出现一个嵌套结构
-
当嵌套的多了就会出现回调地狱的情况
-
比如我们发送三个 ajax 请求
-
第一个正常发送
-
第二个请求需要第一个请求的结果中的某一个值作为参数
-
第三个请求需要第二个请求的结果中的某一个值作为参数
ajax({url: '我是第一个请求',success (res) {// 现在发送第二个请求ajax({url: '我是第二个请求',data: { a: res.a, b: res.b },success (res2) {// 进行第三个请求ajax({url: '我是第三个请求',data: { a: res2.a, b: res2.b },success (res3) { console.log(res3) }})}})} })- 当代码成为这个结构以后,已经没有维护的可能了
- 所以我们要把代码写的更加的艺术一些
-
8、promise
-
promise是一个 ES6 的语法 -
承诺的意思,是一个专门用来解决异步 回调地狱 的问题
-
语法:
new Promise(function (resolve, reject) { // resolve 表示成功的回调 // reject 表示失败的回调 }).then(function (res) {// 成功的函数 }).catch(function (err) {// 失败的函数 })-
promise 就是一个语法
-
我们的每一个异步事件,在执行的时候
-
都会有三个状态,执行中 / 成功 / 失败
-
-
因为它包含了成功的回调函数
-
所以我们就可以使用 promise 来解决多个 ajax 发送的问题
new Promise(function (resolve, reject) {ajax({url: '第一个请求',success (res) {resolve(res)}}) }).then(function (res) {// 准备发送第二个请求return new Promise(function (resolve, reject) {ajax({url: '第二个请求',data: { a: res.a, b: res.b },success (res) {resolve(res)}})}) }).then(function (res) {ajax({url: '第三个请求',data: { a: res.a, b: res.b },success (res) {console.log(res)}}) })
9、 async/await
-
async/await是一个 es7 的语法 -
这个语法是 回调地狱的终极解决方案
-
语法:
async function fn() {const res = await promise对象 } -
可以把异步代码写的看起来像同步代码
-
只要是一个 promiser 对象,那么我们就可以使用
async/await来书写
async function fn() {const res = await new Promise(function (resolve, reject) {ajax({url: '第一个地址',success (res) {resolve(res)}})})// res 就可以得到请求的结果const res2 = await new Promise(function (resolve, reject) {ajax({url: '第二个地址',data: { a: res.a, b: res.b },success (res) {resolve(res)}})})const res3 = await new Promise(function (resolve, reject) {ajax({url: '第三个地址',data: { a: res2.a, b: res2.b },success (res) {resolve(res)}})})// res3 就是我们要的结果console.log(res3)
}
这种方式如果要捕获错误,可以使用try-catch方式
fetch
XMLHttpRequest 是一个设计粗糙的 API,配置和调用方式非常混乱, 而且基于事件的异步模型写起来不友好。
兼容性不好 polyfill: https://github.com/camsong/fetch-ie8,所以还是推荐封装ajax
fetch("http://localhost:3000/users").then(res=>res.json()).then(res=>{console.log(res)})fetch("http://localhost:3000/users",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({username:"kerwin",password:"123"})}).then(res=>res.json()).then(res=>{console.log(res)})fetch("http://localhost:3000/users/5",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({username:"kerwin",password:"456"})}).then(res=>res.json()).then(res=>{console.log(res)})fetch("http://localhost:3000/users/5",{method:"DELETE"}).then(res=>res.json()).then(res=>{console.log(res)})
//错误处理
fetch("http://localhost:3000/users1").then(res=>{if(res.ok){return res.json()}else{// 手动拒绝return Promise.reject({status:res.status,statusText:res.statusText})}}).then(res=>{console.log(res)}).catch(err=>{console.log(err)})
结语
我写过的基于React的项目中,一般会使用将axios(另个一将xhr封装的npm包)二次封装的方式,结合框架进行使用。
相关文章:
JavaScript前后端交互-AJAX/fetch
摘自千峰教育kerwin的js教程 AJAX 1、AJAX 的优势 不需要插件的支持,原生 js 就可以使用用户体验好(不需要刷新页面就可以更新数据)减轻服务端和带宽的负担缺点: 搜索引擎的支持度不够,因为数据都不在页面上…...
动态规划DP 背包问题 完全背包问题(题目分析+C++完整代码)
概览检索 动态规划DP 概览(点击链接跳转) 动态规划DP 背包问题 概览(点击链接跳转) 完全背包问题 原题链接 AcWiing 3. 完全背包问题 题目描述 有 N种物品和一个容量是 V的背包,每种物品都有无限件可用。 第 i种物…...
【cocos creator】【模拟经营】餐厅经营demo
下载:【cocos creator】模拟经营餐厅经营...
JavaScript系列(52)--编译优化技术详解
JavaScript编译优化技术详解 🚀 今天,让我们深入探讨JavaScript的编译优化技术。通过理解和应用这些技术,我们可以显著提升JavaScript代码的执行效率。 编译优化基础概念 🌟 💡 小知识:JavaScript引擎通常…...
【深度学习】softmax回归的从零开始实现
softmax回归的从零开始实现 (就像我们从零开始实现线性回归一样,)我们认为softmax回归也是重要的基础,因此(应该知道实现softmax回归的细节)。 本节我们将使用Fashion-MNIST数据集,并设置数据迭代器的批量大小为256。 import torch from IP…...
【Redis】set 和 zset 类型的介绍和常用命令
1. set 1.1 介绍 set 类型和 list 不同的是,存储的元素是无序的,并且元素不允许重复,Redis 除了支持集合内的增删查改操作,还支持多个集合取交集,并集,差集 1.2 常用命令 命令 介绍 时间复杂度 sadd …...
程序诗篇里的灵动笔触:指针绘就数据的梦幻蓝图<3>
大家好啊,我是小象٩(๑ω๑)۶ 我的博客:Xiao Xiangζั͡ޓއއ 很高兴见到大家,希望能够和大家一起交流学习,共同进步。 今天我们来对上一节做一些小补充,了解学习一下assert断言,指针的使用和传址调用…...
代码随想录-训练营-day16
530. 二叉搜索树的最小绝对差 - 力扣(LeetCode) /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode…...
Vue 3 中的父子组件传值:详细示例与解析
在 Vue 3 中,父子组件之间的数据传递是一个常见的需求。父组件可以通过 props 将数据传递给子组件,而子组件可以通过 defineProps 接收这些数据。本文将详细介绍父子组件传值的使用方法,并通过优化后的代码示例演示如何实现。 1. 父子组件传值…...
谈谈你所了解的AR技术吧!
深入探讨 AR 技术的原理与应用 在科技飞速发展的今天,AR(增强现实)技术已经悄然改变了我们与周围世界互动的方式。你是否曾想象过如何能够通过手机屏幕与虚拟物体进行实时互动?在这篇文章中,我们将深入探讨AR技术的原…...
神经网络的数据流动过程(张量的转换和输出)
文章目录 1、文本从输入到输出,经历了什么?2、数据流动过程是张量,如何知道张量表达的文本内容?3、词转为张量、张量转为词是唯一的吗?为什么?4、如何保证词张量的质量和合理性5、总结 🍃作者介…...
爬取鲜花网站数据
待爬取网页: 代码: import requestsfrom lxml import etree import pandas as pdfrom lxml import html import xlwturl "https://www.haohua.com/xianhua/"header {"accept":"image/avif,image/webp,image/apng,image/sv…...
vue框架技术相关概述以及前端框架整合
vue框架技术概述及前端框架整合 1 node.js 介绍:什么是node.js Node.js就是运行在服务端的JavaScript。 Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎。 作用 1 运行java需要安装JDK,而Node.js是JavaScript的运行环…...
深入解析 C++ 字符串处理:提取和分割的多种方法
在 C 编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时。本文将详细探讨如何使用 C 标准库中的工具(如 std::istringstream 和 std::string 的成员函数)来提取和分割字符串,并分析不同方法的适…...
数据结构 树2
文章目录 前言 一,二叉搜索树的高度 二,广度优先VS深度优先 三,广度优先的代码实现 四,深度优先代码实现 五,判断是否为二叉搜索树 六,删除一个节点 七,二叉收索树的中序后续节点 总结 …...
NeetCode刷题第19天(2025.1.31)
文章目录 099 Maximum Product Subarray 最大乘积子数组100 Word Break 断字101 Longest Increasing Subsequence 最长递增的子序列102 Maximum Product Subarray 最大乘积子数组103 Partition Equal Subset Sum 分区等于子集和104 Unique Paths 唯一路径105 Longest Common Su…...
Google Chrome-便携增强版[解压即用]
Google Chrome-便携增强版 链接:https://pan.xunlei.com/s/VOI0OyrhUx3biEbFgJyLl-Z8A1?pwdf5qa# a 特点描述 √ 无升级、便携式、绿色免安装,即可以覆盖更新又能解压使用! √ 此增强版,支持右键解压使用 √ 加入Chrome增强…...
[EAI-027] RDT-1B,目前最大的用于机器人双臂操作的机器人基础模型
Paper Card 论文标题:RDT-1B: a Diffusion Foundation Model for Bimanual Manipulation 论文作者:Songming Liu, Lingxuan Wu, Bangguo Li, Hengkai Tan, Huayu Chen, Zhengyi Wang, Ke Xu, Hang Su, Jun Zhu 论文链接:https://arxiv.org/ab…...
什么是Rust?它有什么特点?为什么要学习Rust?
什么是Rust?它有什么特点?为什么要学习Rust? 如果你是一名编程初学者,或者已经有一些编程经验但对Rust感兴趣,那么这篇文章就是为你准备的!我们将用简单易懂的语言,带你了解Rust是什么、它有什…...
[EAI-028] Diffusion-VLA,能够进行多模态推理和机器人动作预测的VLA模型
Paper Card 论文标题:Diffusion-VLA: Scaling Robot Foundation Models via Unified Diffusion and Autoregression 论文作者:Junjie Wen, Minjie Zhu, Yichen Zhu, Zhibin Tang, Jinming Li, Zhongyi Zhou, Chengmeng Li, Xiaoyu Liu, Yaxin Peng, Chao…...
AIP-134 标准方法:Update
编号134原文链接AIP-134: Standard methods: Update状态批准创建日期2019-01-24更新日期2022-06-02 REST API通常向资源URI(如 /v1/publishers/{publisher}/books/{book} )发出 PATCH 或 PUT 请求,更新资源。 面向资源设计(AIP-…...
计算机网络一点事(24)
TCP可靠传输,流量控制 可靠传输:每字节对应一个序号 累计确认:收到ack则正确接收 返回ack推迟确认(不超过0.5s) 两种ack:专门确认(只有首部无数据) 捎带确认(带数据…...
DIFY源码解析
偶然发现Github上某位大佬开源的DIFY源码注释和解析,目前还处于陆续不断更新地更新过程中,为大佬的专业和开源贡献精神点赞。先收藏链接,后续慢慢学习。 相关链接如下: DIFY源码解析...
Kafka SSL(TLS)安全协议
文章目录 Kafka SSL(TLS)安全协议1. Kafka SSL 的作用1.1 数据加密1.2 身份认证1.3 数据完整性1.4 防止中间人攻击1.5 确保安全的分布式环境1.6 防止拒绝服务(DoS)攻击 2. Kafka SSL 配置步骤(1)创建 SSL 证…...
hexo部署到github page时,hexo d后page里面绑定的个人域名消失的问题
Hexo 部署博客到 GitHub page 后,可以在 setting 中的 page 中绑定自己的域名,但是我发现更新博客后绑定的域名消失,恢复原始的 githubio 的域名。 后面搜索发现需要在 repo 里面添加 CNAME 文件,内容为 page 里面绑定的域名&…...
【Block总结】MAB,多尺度注意力块|即插即用
文章目录 一、论文信息二、创新点三、方法MAB模块解读1、MAB模块概述2、MAB模块组成3、MAB模块的优势 四、效果五、实验结果六、总结代码 一、论文信息 标题: Multi-scale Attention Network for Single Image Super-Resolution作者: Yan Wang, Yusen Li, Gang Wang, Xiaoguan…...
移动互联网用户行为习惯哪些变化,对小程序的发展有哪些积极影响
一、碎片化时间利用增加 随着生活节奏的加快,移动互联网用户的碎片化时间越来越多。在等公交、排队、乘坐地铁等间隙,用户更倾向于使用便捷、快速启动的应用来满足即时需求。小程序正好满足了这一需求,无需下载安装,随时可用&…...
使用UpdateCursor删除行
UpdateCursor除了可以编辑表或要素类的行外,还可以删除行.但要记住,在编辑会话外删除行时,更改是永久性的. 操作方法: 1.打开IDLE,新建一个脚本 2.导入arcpy和os模块 import arcpy import os 3.设置工作空间 arcpy.env.workspace "<>" 4.在with语句中新…...
使用 Tauri 2 + Next.js 开发跨平台桌面应用实践:Singbox GUI 实践
Singbox GUI 实践 最近用 Tauri Next.js 做了个项目 - Singbox GUI,是个给 sing-box 用的图形界面工具。支持 Windows、Linux 和 macOS。作为第一次接触这两个框架的新手,感觉收获还蛮多的,今天来分享下开发过程中的一些经验~ 为啥要做这个…...
1.4 Go 数组
一、数组 1、简介 数组是切片的基础 数组是一个固定长度、由相同类型元素组成的集合。在 Go 语言中,数组的长度是类型的一部分,因此 [5]int 和 [10]int 是两种不同的类型。数组的大小在声明时确定,且不可更改。 简单来说,数组…...
