Vue3优雅地处理异步任务轮询
在许多应用程序中,我们经常需要执行定期的异步任务轮询。例如,从后端获取实时数据、更新UI状态、发送心跳请求等等。传统的定时器函数setInterval
提供了一种方式来实现任务轮询,但它的用法在某些情况下可能不够灵活,容易出现一些问题,比如处理异步回调、处理清理操作等。
为了解决这些问题,我们可以借助Vue 3提供的onUnmounted
钩子函数和ref
响应式引用,创建一个名为useIntervalAsync
的自定义Hook,它可以更好地处理异步任务轮询,并提供更好的控制和清理机制。
useIntervalAsync的实现
首先,让我们来看一下useIntervalAsync
的实现。它接受三个参数:callback
回调函数、delay
延迟时间和unit
时间单位。它返回一个包含flush
、cancel
和recover
方法的对象,用于控制任务轮询的行为。
import { onUnmounted, ref } from 'vue';
import { TimeUnit, toMilliseconds } from '@tmp/utils';
export type Cleanup = () => any;
export type CallbackReturn = void | Cleanup;
export type Callback = (...args: any[]) => CallbackReturn | Promise<CallbackReturn>;
export const useIntervalAsync = (callback: Callback, delay: number, unit: TimeUnit = 'millisecond') => {
const timeout = ref<number | null>(null);
const canceled = ref<boolean>(false);
const cleanup = ref<Cleanup | void>();
// 将延迟时间转换为毫秒
delay = toMilliseconds(delay, unit);
const run: TimerHandler = async () => {
if (canceled.value) {
return;
}
// 清理之前的回调函数
if (typeof cleanup.value === 'function') {
cleanup.value();
}
// 执行回调函数并获取清理函数
cleanup.value = await Promise.resolve(callback());
// 设置下一次任务轮询的定时器
timeout.value = globalThis.setTimeout(run, delay);
};
// 初始化任务轮询
run();
// 刷新任务轮询,取消当前定时器,重新执行回调函数
const flush = () => {
timeout.value && globalThis.clearTimeout(timeout.value);
run();
};
// 取消任务轮询,清理定时器和回调函数
const cancel = () => {
timeout.value && globalThis.clearTimeout(timeout.value);
canceled.value = true;
if (typeof cleanup.value === 'function') {
cleanup.value();
}
};
// 恢复任务轮询,重新启动定时器
const recover = () => {
canceled.value = false;
flush();
};
// 在组件卸载时取消任务轮询
onUnmounted(() => {
cancel();
});
return {
flush,
cancel,
recover,
};
};
export default useIntervalAsync;
如何使用useIntervalAsync
现在我们已经实现了useIntervalAsync
,让我们看看如何使用它来优化异步任务轮询。
首先,我们需要在Vue组件中引入useIntervalAsync
:
<script lang="ts" setup>
import { useIntervalAsync } from '@/hooks/useIntervalAsync';
const { flush, cancel, recover } = useIntervalAsync(async () => {
let timeout: any = null;
await new Promise((resolve) => {
timeout = setTimeout(() => {
console.log('模拟异步事件');
resolve('');
}, 2000);
});
return () => {
clearTimeout(timeout);
};
}, 1000);
</script>
<template>
<div>
<button @click="flush">刷新</button>
<button @click="cancel">取消</button>
<button @click="recover">恢复</button>
</div>
</template>
在上面的示例中,我们定义了一个使用useIntervalAsync
的组件,并将异步任务的回调函数作为参数传递给useIntervalAsync
。在这个回调函数中,我们可以执行任何异步操作,如从后端获取数据、更新UI状态等。
我们还可以使用flush
方法来手动触发任务轮询,cancel
方法来取消任务轮询,以及recover
方法来恢复任务轮询。这些方法可以根据实际需求在组件中进行调用。
为什么需要useIntervalAsync
使用useIntervalAsync
可以带来一些好处:
- 更好的异步任务控制:
useIntervalAsync
提供了灵活的方式来处理异步任务轮询,可以根据需要执行异步操作,并在下次任务轮询之前执行清理操作。 - 更好的内存管理:
useIntervalAsync
在组件卸载时会自动取消任务轮询,清除定时器并执行清理操作,从而避免内存泄漏。 - 更好的代码可读性和可维护性:使用
useIntervalAsync
可以将任务轮询的逻辑封装为一个可复用的Hook,使代码更具可读性和可维护性。
总结起来,useIntervalAsync
是一个用于优化异步任务轮询的自定义Hook,它提供了更好的控制和清理机制,帮助我们更好地处理定期执行的异步任务。
无论是从性能优化的角度还是代码结构的角度,useIntervalAsync
都是一个有用的工具,可以让我们更好地处理异步任务轮询的需求。
希望本文能帮助你理解并有效地使用useIntervalAsync
,提高你的应用程序的性能和可维护性。
Happy coding!
转载自:https://juejin.cn/post/7235906887849820215