前端编程训练 异步编程篇 请求接口 vue与react中的异步
文章目录
- 前言
- 代码执行顺序的几个关键点
- 接口请求
- vue与react中的异步
- vue中的异步
- react的state修改异步
前言
本文是B站三十的前端课的笔记前端编程训练,异步编程篇
代码执行顺序的几个关键点
- 我们可以理解为代码就是一行一行,一句一句是执行(定义变量,方法存在提升情况)
- 如果有复杂表达式,表达式从右往左执行(赋值,方法调用,三元等等)
- 异步特性,代码一行行执行,但是我们调用了一个异步操作,JS放入异步队列中,等待任务完成,并且当前这次执行已经完成,则执行异步部分
接口请求
接口请求是我们日常工作中最常见的异步操作,通常接口的请求是时间不定的,肯定要花一点时间的。接口请求的异步我们不用考虑什么微任务和宏任务
- 获取前三用户的积分,做一个图表。但是问题在于,图表x轴的日期,在一个接口。用户列表在一个接口,用户积分又是另外一个接口
利用async await
一步一步就可以实现但是必须请求完上一个请求才能执行下一步代码会影响性能 我们可不可以让没有依赖的请求同时并发从而优化性能并节省时间呢
<script setup>
import * as echarts from "echarts"
import { onMounted} from "vue";
import axios from "axios";
async function getFinnalData() {
//请求最近五天的日期
const res = await axios.get("http://localhost:8000/getDate")
const dateList = res.data.recentDate;
//获取所有用户列表
const userRes = await axios.get("http://localhost:8000/getUser")
const userList = userRes.data.userList;
//按id排序
userList.sort((preuser, nowuser) => {
return preuser.id - nowuser.id;
})
//筛选出id前三的
userList.splice(3, userList.length - 1);
const _seriesArr = []
for (let i = 0; i < userList.length; i++) {
let _userNumberRes = await axios.get("http://localhost:8000/getUserNumber?id=" + userList[i].id)
let _series = {
name: _userNumberRes.data.name,
data: _userNumberRes.data.recentNumber,
type: "line",
}
_seriesArr.push(_series);
}
//所有数据都到位了,构建最终的options
let option = {
yAxis: {
type: "value"
},
tooltip: {},
xAxis: {
type: "category",
data: dateList
},
series: _seriesArr
}
return option;
}
onMounted(() => {
getFinnalData()
})
</script>
使用Promise.all实现并发效果
优化性能并节省时间
function getFinnalData() {
let option = {
yAxis: {
type: "value"
},
tooltip: {},
xAxis: {
type: "category",
data: []
},
series: []
}
//Promise.all,会等数组里两个Promise异步操作都返回了才进入then
Promise.all([
axios.get("http://localhost:8000/getDate"),
axios.get("http://localhost:8000/getUser")
]).then((res) => {
//res[0]-日期接口的返回 res[1]-用户列表接口的返回
//日期数据取出来作为x轴
option.xAxis.data = res[0].data.recentDate
//取出用户列表
const userList = res[1].data.userList
//排序
userList.sort((preuser, nowuser) => {
return preuser.id - nowuser.id;
})
//筛选出id前三的
userList.splice(3, userList.length - 1);
//Promise.all保证三个接口都请求成功了,在进行series的操作
Promise.all([
axios.get("http://localhost:8000/getUserNumber?id=" + userList[0].id),
axios.get("http://localhost:8000/getUserNumber?id=" + userList[1].id),
axios.get("http://localhost:8000/getUserNumber?id=" + userList[2].id)
]).then((res) => {
//三个请求都完成进入then
res.forEach((singleUserNumberres) => {
let _series = {
name: singleUserNumberres.data.name,
data: singleUserNumberres.data.recentNumber,
type: 'line'
}
option.series.push(_series);
//执行完上面的85行,数据就完整了。
let chartDom = document.getElementById('container');
let myChart = echarts.init(chartDom);
myChart.setOption(option);
})
})
})
}
- 把一个大数组拆分成10个一组,发送给接口,如果有失败的则重试,试超过三次还没成功则停止发送
<script setup>
import axios from "axios";
//循环形成一个100个元素的数组
const arr = [];
for (let i = 0; i < 100; i++) {
arr.push(i);
}
let tryTime = 0;
async function sendSingle(part) {
const res = await axios.get("http://localhost:8001/sendData?part=" + part)
if (!res.data.success) {
tryTime += 1;
if (tryTime >= 3) {
//重试超过三次还没成功,
//就中断后续请求
return false
} else {
return await sendSingle(part);
}
//请求失败的时候进这里
} else {
//如果成功了,我们就把重试次数归0
tryTime = 0;
return true
}
}
async function send() {
//每次循环发一组出去
for (let j = 0; j < arr.length; j += 10) {
const part = arr.slice(j, j + 10);
const res = await sendSingle(part);
if (!res) {
break;
}
}
}
send();
</script>
3,请求接口,根据接口的返回日期,比对本地缓存的日期,看有没有过期
决定是从本地读取key,还是从接口请求key。然后再拿着key请求下一个接口
<script setup>
import { ref } from "vue";
import axios from "axios";
const keyValue = ref('');
axios.get("http://localhost:8002/getAvailableDate").then(async (res) => {
if (new Date() - new Date(res.data.date) < 0) {
//没过期
const _key = localStorage.getItem('key')
keyValue.value = _key
} else {
//已过期
const _key = await axios.get("http://localhost:8002/getNew")
keyValue.value = _key.data.key
}
axios.get("http://localhost:8002/getFinnalDate?key=" + keyValue.value).then((res) => {
})
})
</script>
- 对身份证输入进行三次验证,但是其中同异步验证交杂上一个验证通过才开始下一个,不通过就直接报错,前端验证长是否18位-身份证是否占用-前端验证身份证格式是否符合-身份证是否真实
<script setup>
import axios from "axios";
const value = "112301199402313013";
const testArr = [
(value) => {
if (value.length === 18) {
return true
} else {
return false
}
},
async (value) => {
//这个写成async或者直接return axios.get()都是可以的
const res = await axios.get('http://localhost:8003/isExit?value=' + value);
return !res.data.data
},
(value) => {
const reg = /^[1-9]\d{5}(18|19|20|21|22)?\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}(\d|[Xx])$/
return reg.test(value)
},
async (value) => {
const res = await axios.get('http://localhost:8003/isReal?value=' + value);
return res.data.data
}
]
async function test(value) {
for (let i = 0; i < testArr.length; i++) {
const res = await testArr[i](value)
if (!res) {
alert("验证失败")
break;
}
}
}
test(value)
</script>
vue与react中的异步
vue中的异步
在页面更新和DOM操作时,vue
中的nextTick有大作用
<script setup>
import axios from "axios";
import { nextTick, ref } from "vue";
const videolist = ref([]);
// extTick是在DOM更新完成后执行的回调函数。Vue是响应式的,当你更新了videolist(例如videolist.value = res.data.videoList),Vue会标记这个数据为"已改变",并且会异步更新DOM。也就是说,页面更新不会立即发生,而是会在下一个事件循环中进行。所以,如果你直接操作DOM(如获取视频元素并调用play方法),可能会发现这些视频元素还没有更新到页面上。nextTick确保你可以在DOM更新后再执行相关操作。
//请求接口-》拿到接口的返回给到videoLsit-》页面根据videoList更新-》更新完成后,获取到所有的videodom-》调用play方法
function show() {
axios.get("http://localhost:8000/videoList").then((res) => {
// 响应式数据更新 页面不会立即跟新
videolist.value = res.data.videoList
//setTimeout或者nextTick可以立即更新
// nextTick(() => {
// const videoArr = document.getElementById("container").getElementsByTagName('video');
// for (let i = 0; i < videoArr.length; i++) {
// videoArr[i].play();
// }
// })
setTimeout(() => {
const videoArr = document.getElementById("container").getElementsByTagName('video');
for (let i = 0; i < videoArr.length; i++) {
videoArr[i].play();
}
})
})
}
</script>
<template>
<button @click="show">加载</button>
<div id="container" class="container">
<div class="video" v-for="video in videolist">
<h3>{{ video.name }}</h3>
<video :src="video.videoSrc" muted></video>
</div>
</div>
</template>
<script setup>
import axios from "axios";
import { nextTick, ref } from "vue";
//请求接口-》渲染列表-》判断列表长度-》修改是否显示总长度的控制变量
const tagList = ref([]);
const needShowLength = ref(false);
axios.get("http://localhost:8000/tagList").then((res) => {
tagList.value = res.data.tagList
nextTick(() => {
const width = document.getElementById("container").clientWidth;
if (width > 800) {
needShowLength.value = true;
} else {
needShowLength.value = false;
}
})
})
</script>
<template>
<div id="container" class="container">
<div class="tag" v-for="item in tagList">{{ item }}</div>
</div>
<div v-if="needShowLength">总个数:{{ tagList.length }}</div>
</template>
react的state修改异步
react中修改state数据是异步的不是马上更新的。所以我们可以看这样例子
一般方案useEffact监听数据改变,如果可以的话改成用useRef,setTimout不行
function App() {
// const [name, setName] = useState('')
// const [id, setId] = useState('')
// const [age, setAge] = useState('')
// useEffect(() => {
// if (name == '' && age == '' && id == '') {
// axios.get(`http://localhost:8000/tagList?name=${name}&age=${age}&id=${id}`)
// }
// }, [name, age, id]).
const name = useRef('');
const id = useRef('');
const age = useRef('');
return (
<div className="App">
姓名:<input className='input' onChange={(e) => {
name.current = e.target.value
}}></input>
学号:<input className='input' onChange={(e) => {
id.current = e.target.value
}}></input>
年龄:<input className='input' onChange={(e) => {
age.current = e.target.value
}}></input>
<button onClick={() => {
axios.get(`http://localhost:8000/tagList?name=${name.current}&age=${age.current}&id=${id.current}`)
}}>确认</button>
<button onClick={() => {
const inputList = document.getElementsByClassName("input")
for (let i = 0; i < inputList.length; i++) {
console.log(i);
inputList[i].value = ''
}
name.current = '';
id.current = '';
age.current = '';
axios.get(`http://localhost:8000/tagList?name=${name.current}&age=${age.current}&id=${id.current}`)
}}>重置</button>
</div>
);
}
文章到这里就结束了 谢谢大家