了解到浏览器处理线程的时候会按照同步和异步的顺序进行的。
在我们开发的过程的中一些methods往往是是采用异步的写法当众多操作叠加到一起的时候顺序就无法保证,比如说搜索而言,在进行数据检索的时候之前的结果还没有出来,就进行了下一步的搜索或者新建等操作,这时就需要我们去确保线程的顺序。
解决办法:
①在进行操作的时候添加loading效果设置为true,这时就可以防止其他操作的运行,loading可以封装为一个组件给全局使用。但显然有时加载时间过长往往会个用户不好的体验,所以需要慎重使用
②对于异步操作进行加锁处理可以采用ahooks的useLockFn进行包裹他是个方法把异步的操作作为参数
import { useLockFn } from 'ahooks'
③取消过期的请求
当进行新的请求操作时可以把之前未完成的请求取消。可以采用浏览器自带的AbortControllerd(api)
简单的话就是使用controller.signal传入请求函数中,在需要时调用controller.abort去取消请求
const controller = new AbortController();
封装成hook
import { useUnmount } from 'ahooks';
import { useRef } from 'react';
export function useAbortController() {
const controller = useRef<AbortController>(new AbortController());
useUnmount(() => {
controller.current.abort();
});
return {
signal: controller.current.signal,
abort: controller.current.abort,
};
}
使用第三方库也能实现
import { createImperativePromise } from 'awesome-imperative-promise';
function App() {
// 发送异步请求
const getData = async () => {
const resp = await axios.get('/xxx')
}
const { cancel } = createImperativePromise(getData)
function handleClick() {
cancel()
getData()
}
return (
<button onClick={handleClick}>发送请求</div>
)
}
④忽略过期请求
利用变量latest记录最新一次请求的时间戳
在发出请求时,使用当前时间戳标记这次请求的id
在请求结束后,当且仅当id取值与latest相等时,才更新数据/视图
import dayjs from 'dayjs'
function App() {
const latest = useRef<string>('')
// 发送异步请求
const getData = async () => {
// 当前时间戳(毫秒)
const id = String(dayjs().unix() * 1000)
latest.current = id
const resp = await axios.get('/xxx')
if (id === latest.current) {
// 更新数据/视图
}
}
function handleClick() {
getData()
}
return (
<button onClick={handleClick}>发送请求</div>
)
}