🎯 你正在阅读「半路出家玩前端」系列文章 🎯
🔥 弹简特 个人主页
❄️ 个人专栏直通车:
- 🔌 接口测试从入门到跑路
- ☕ 一个后端的 JavaEE 续命指南
- 🛜 网络原理续命手册
- ☕ Java项目-轻聊
- ☕ Java项目-企悦抽
✨ 靠热爱去书写自己,靠勇敢去书写生活!
🌟 博主简介:

文章目录:
- 一、前言
- 二、案例演示
- 三、详细介绍
-
- 0、先看全局:我们最终要会什么
- 1、同步和异步:别让页面干等
- 2、Promise:异步结果的「状态盒」
-
- [2.1 Promise三个状态](#2.1 Promise三个状态)
- [2.2 怎么创建一个 Promise](#2.2 怎么创建一个 Promise)
- [2.3 用 then / catch 接结果](#2.3 用 then / catch 接结果)
- [3、async:让函数自动返回 Promise](#3、async:让函数自动返回 Promise)
-
- [3.1 加了 async,返回值会发生什么](#3.1 加了 async,返回值会发生什么)
- [3.2 async 带来的好处](#3.2 async 带来的好处)
- 4、await:等结果回来再往下走
-
- [4.1 为什么要等](#4.1 为什么要等)
- [4.2 必须记住的规则](#4.2 必须记住的规则)
- [4.3 async + await 一起用的本质](#4.3 async + await 一起用的本质)
- 5、Axios:真正向后端要数据
-
- [5.1 相关概念](#5.1 相关概念)
- [5.2 安装](#5.2 安装)
- [5.3 最小请求写法](#5.3 最小请求写法)
- [6、接到 Vue:土味情话示例](#6、接到 Vue:土味情话示例)
-
- [6.1 推荐实现顺序](#6.1 推荐实现顺序)
- [6.2 完整代码](#6.2 完整代码)
- [6.3 成功回调里到底拿到什么](#6.3 成功回调里到底拿到什么)
- [6.4 赋值方式:保住响应式](#6.4 赋值方式:保住响应式)
- [6.5 什么时候必须 await](#6.5 什么时候必须 await)
- [7、跨域:5173 访问 8080 被拦截](#7、跨域:5173 访问 8080 被拦截)
- 8、底层:这些对象住在哪里
一、前言
铁汁么,我们前端终归是要和后端交互的,那么在和后端交互的时候,我们需要请求后端,那么到底是同步请求还是异步请求,我们本期就将他梳理清楚。
二、案例演示
1、项目结构

2、根组件代码
html
<!--
土味情话页面:
1) onMounted / 按钮 → 调用 getLoveMessage
2) Axios 请求后端 http://localhost:8080/api/情话
3) 取 response.data,用 Object.assign 写入 reactive,模板回显
前置:后端已启动,并配置 @CrossOrigin 允许跨域
-->
<script setup>
import { reactive, onMounted } from 'vue'
import axios from 'axios'
/**
* 页面模型(响应式对象)
* 先给默认字段;请求成功后用 Object.assign 覆盖属性值
* 注意:不要整对象替换(jsonData = xxx),否则响应式可能失效
*/
const jsonData = reactive({
code: 0,
content: '加载中...',
})
/**
* 向后端拉取一句土味情话
* - async:本函数返回 Promise
* - await:等 Axios 结果回来再往下执行(否则打印/赋值会抢跑)
*/
async function getLoveMessage() {
try {
// axios(...) 返回 Promise;成功时拿到完整响应对象 response
const response = await axios({
method: 'get', // 查询用 get
// 与后端 Controller 映射路径保持一致
url: 'http://localhost:8080/api/情话',
// params: { username: 'admin' }, // GET 查询参数(拼到 URL)
// data: { ... }, // 请求体(POST 常用)
})
// response:Axios 包装的响应(含 status、headers、data...)
// response.data:后端返回的业务 JSON,例如 { code, content }
// 若后端还有统一 Result 包装,可能是 response.data.data
console.log('完整响应对象:', response)
console.log('业务 JSON:', response.data)
// 属性对拷到原 reactive 对象,保持响应式
Object.assign(jsonData, response.data)
} catch (e) {
// 网络错误、跨域被拦、后端 4xx/5xx 等都会进这里
console.error('请求失败(先检查后端是否启动、是否跨域):', e)
jsonData.content = '请求失败,请检查后端与跨域配置'
}
}
/**
* 生命周期:模板挂载完成后执行
* 一进页面就自动拉一句情话
*/
onMounted(() => {
getLoveMessage()
})
</script>
<template>
<div class="page">
<h2>今日土味情话</h2>
<p class="content">{{ jsonData.content }}</p>
<p class="meta" v-if="jsonData.code">编号:{{ jsonData.code }}</p>
<!-- 点击再次请求;后端若做随机,每次内容可不同 -->
<button type="button" @click="getLoveMessage">再来一句</button>
</div>
</template>
<style scoped>
.page {
max-width: 520px;
margin: 40px auto;
padding: 24px;
text-align: left;
}
.content {
font-size: 18px;
line-height: 1.6;
min-height: 3em;
padding: 12px;
background: #f6f8fa;
border-radius: 8px;
}
.meta {
color: #666;
font-size: 14px;
}
button {
margin-top: 12px;
padding: 8px 16px;
cursor: pointer;
}
</style>
代码解释:


3、程序入口
js
/**
* 应用入口:创建 Vue 应用并挂到页面
* 本示例不需要路由 / Pinia,页面逻辑都在 App.vue
*/
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')
4、测试



三、详细介绍
0、先看全局:我们最终要会什么
text
会分辨同步 / 异步
↓
会看 Promise 三状态(结果包装盒)
↓
会用 then / catch(或 async/await)处理成功失败
↓
会用 Axios 发请求,取出 response.data
↓
会赋给 Vue 的响应式数据并显示
↓
会处理跨域(前后端口不同时)
1、同步和异步:别让页面干等

| 同步 | 异步 | |
|---|---|---|
| 含义 | 上一件不完,下一件不开始 | 先发出去,主流程继续;有结果再处理 |
| 类比 | 打电话:必须聊完才能干别的 | 发微信:发出去就能干别的,对方回了再看 |
| 前端请求 | 干等时页面体验差 | 日常开发默认用异步 |
定时器「两秒后再执行」也是异步:任务自己跑,主线程不等。
异步请求发出后,浏览器不用卡死;结果回来时,用回调处理即可。
2、Promise:异步结果的「状态盒」
Promise 是异步编程的一种解决方案:一次 Ajax 不论成功还是失败,都可以把结果状态装进这个盒子里。
它是 ES 里的一种对象类型,new Promise 的感觉接近 Java 里 new 一个对象。
2.1 Promise三个状态

| 状态 | 常见英文 | 何时出现 |
|---|---|---|
| 进行中 | pending |
请求已发出,结果还没回来 |
| 成功 | fulfilled(通过 resolve) |
正常数据回来(如 HTTP 200) |
| 失败 | rejected(通过 reject) |
出错(4xx/5xx、网络失败等) |
要点:
- 最终落点只有两种:成功或失败;再加上「进行中」。
- 不能既成功又失败,只能二选一。
- 成功时把数据放进盒子;失败时通常是错误信息。
2.2 怎么创建一个 Promise
构造函数里传入回调,回调有两个参数,都是函数:
resolve(数据)→ 保存成功reject(错误)→ 保存失败
参数名可以自定,关键是你调用了哪一个。
javascript
const p = new Promise(function (resolve, reject) {
// 二选一:
resolve('后端返回的成功数据')
// reject(new Error('失败了'))
})
2.3 用 then / catch 接结果
成功、失败都要用回调来接。两种写法:
写法 A:两个回调都放 then
javascript
p.then(
(value) => { /* 成功:value 就是 resolve 传来的值 */ },
(err) => { /* 失败 */ }
)
写法 B:推荐------成功和失败分开,结构更清晰
javascript
p.then((value) => {
console.log('成功', value) // 拿到数据后想干嘛自己定
}).catch((err) => {
console.log('失败', err) // 一般是 Error
})
说明:业务里很少手写 new Promise,但 Axios 返回的就是 Promise,所以三状态和 then/catch 必须懂。真正写项目时,重点往往在「成功回调里怎么用数据」。
3、async:让函数自动返回 Promise
async / await 是更晚的 ES 语法关键字。先看 async。

3.1 加了 async,返回值会发生什么
javascript
async function getTen() {
return 10
}
const result = getTen()
// result 不是数字 10,而是一个 Promise
// 相当于:成功结果为 10 的 Promise
可以对比后端「统一 Result」:真实数据被包了一层,这一层表示成功或失败。
| 函数内部 | 调用方拿到的 Promise |
|---|---|
return 普通值 |
成功,值为该值 |
throw new Error('...') |
失败(前端统一用 Error) |
return 已有的 Promise |
沿用该 Promise 的成功/失败 |
javascript
async function ok() {
return 10
}
async function fail() {
throw new Error('出错了')
}
ok().then((v) => console.log(v)) // 10
fail().catch((e) => console.log(e)) // Error
3.2 async 带来的好处
不必到处手写 new Promise:直接返回数据或抛错,运行时帮你包装成 Promise。
拿到 Promise 后,再用 then / catch 处理(二者只会走一边)。
4、await:等结果回来再往下走
await 的字面意思就是等待。
4.1 为什么要等
假设 fun2 里要用到 fun1 的返回值:
javascript
async function fun1() {
return 10 // 被包装成成功 Promise
}
async function fun2() {
const res = await fun1()
// 等 fun1 完成;成功时 res 直接是 10,不是 Promise 对象
console.log(res) // 10
// 后面的代码依赖 res,所以必须等
}
如果去掉 await:fun1 异步执行,下一行可能已经跑了,此时 res 还没就绪------拿不到真正的值。
4.2 必须记住的规则
| 规则 | 说明 |
|---|---|
有 await → 函数必须是 async |
否则报错 |
有 async → 可以没有 await |
允许 |
await 右侧多为 Promise |
普通值也可以 |
| 右侧 Promise 失败 | 抛异常,用 try/catch 捕获 |
javascript
async function demo() {
try {
const data = await someAsyncCall()
console.log(data) // 成功值
} catch (e) {
console.log('失败', e) // 不必再手写一长串 then/catch
}
}
await 会卡住当前这段异步函数的后续语句:右边没结束,后面先不执行。
4.3 async + await 一起用的本质
async:把返回值封进 Promiseawait:把成功 Promise拆成真实值
中间封/拆不用自己管,所以一般不必再 new Promise + then。这就是日常推荐写法。
5、Axios:真正向后端要数据
Axios 是基于 Promise 的网络请求库,封装了 Ajax,可在浏览器 / Node 中使用。
5.1 相关概念
| 名词 | 含义 |
|---|---|
| Ajax | Asynchronous JavaScript And XML,异步请求的统称 |
| 数据格式 | 早期常见 XML,现在主流是 JSON |
XMLHttpRequest |
浏览器侧异步请求对象 |
| Axios | 帮你发请求、用 Promise 包装结果,还可配合拦截器等 |
注意:浏览器发异步请求,后端该怎么分层还怎么分层;变的是前端交互------不必整页干等,结果回来做局部更新即可。
5.2 安装
bash
npm i axios
npm run dev
5.3 最小请求写法
javascript
import axios from 'axios' // 默认导出,变量名可叫 axios / http
axios({
method: 'get', // get查询 / post添加 / put修改 / delete删除
url: 'http://localhost:8080/api/情话',
// params: { username: 'admin' }, // 拼到 URL ?key=value,GET 常用
// data: { username: 'admin' }, // 放请求体,POST 常用
})
.then((response) => {
console.log(response.data) // 业务 JSON 在 data 里
})
.catch((error) => {
console.log(error)
})
| 配置 | 作用 |
|---|---|
method |
请求方式 |
url |
后端地址 |
params |
查询参数(URL 后);后端常用 @RequestParam |
data |
请求体;后端常用 @RequestBody |
Axios 调用返回 Promise ,因此可以接 then/catch,也可以 await。
6、接到 Vue:土味情话示例
需求示例:后端 http://localhost:8080/api/情话 返回 { code, content },页面显示情话,按钮可再刷一句。

6.1 推荐实现顺序
text
准备 reactive 模型
→ 编写请求函数(axios + await)
→ onMounted 进页拉一次
→ 按钮再拉一次
→ Object.assign 写入模型
→ 模板绑定 content
6.2 完整代码
html
<script setup>
import { reactive, onMounted } from 'vue'
import axios from 'axios'
const jsonData = reactive({
code: 0,
content: '',
})
async function getLoveMessage() {
try {
const response = await axios({
method: 'get',
url: 'http://localhost:8080/api/情话',
})
// response:完整响应对象
// response.data:后端 JSON
Object.assign(jsonData, response.data)
} catch (e) {
console.log('请求失败', e)
}
}
onMounted(() => {
getLoveMessage() // 模板就绪后要数据
})
</script>
<template>
<div>
<h3>今日土味情话</h3>
<p>{{ jsonData.content }}</p>
<button type="button" @click="getLoveMessage">再来一句</button>
</div>
</template>
6.3 成功回调里到底拿到什么
text
response ← Axios 给的响应对象
├─ status / headers ...
└─ data ← 后端返回的 JSON
├─ code
└─ content ← 页面要显示的字段
若后端还有统一 Result 包装:
text
response.data → Result
response.data.data → 真正业务数据(可能需要点两层 data)
调试建议:先 console.log(response),或在 Network / 断点里看对象结构,再决定取哪一层。
6.4 赋值方式:保住响应式
javascript
// 错误:整对象替换,引用变了,响应式容易失效
// jsonData = backData
// 正确:属性拷贝到原对象上
Object.assign(jsonData, backData)
// 字段很少时也可以:
// jsonData.code = backData.code
// jsonData.content = backData.content
6.5 什么时候必须 await
若请求后面还要立刻使用数据(例如打印、二次计算),必须 await,并且函数声明为 async。
若后面没有任何依赖结果的代码,可以不 await。
不加 await 就往下跑,常见现象:打印出来仍是空对象------数据还没赋上去。
7、跨域:5173 访问 8080 被拦截
前端开发服务器(如 5173)和后端(如 8080)只要协议 / 域名 / 端口有一个不同,就是跨域。浏览器会拦截不安全的跨源请求。
典型报错关键词:
text
CORS policy / blocked / Access-Control-Allow-Origin
开发期常见处理(Java 后端示例):在 Controller 上允许跨域:
java
@CrossOrigin
@RestController
public class LoveController {
// ...
}
放行后响应头会出现类似 Access-Control-Allow-Origin: *,请求才能进入成功回调。
生产环境通常配置更精确的允许来源,或用网关 / 反向代理。
8、底层:这些对象住在哪里

| 名字 | 更像存在哪 | 内容 |
|---|---|---|
变量 response |
栈上的引用 | 指向堆对象 |
| Promise | 堆 | 状态 + 成功值 / 失败原因 |
response 对象 |
堆 | status、headers、data... |
response.data |
堆 | 业务 JSON |
reactive(jsonData) |
堆中的响应式对象 | Object.assign 改字段、不换地址 |
text
await axios(...)
→ Promise:pending → fulfilled
→ 得到 response
→ 取出 data
→ 拷贝进 reactive
→ 视图更新
OK,本期我们先介绍到这里,下一期我们将补充Axios的get和post请求以及拦截器等等工作。