面试题答案
一键面试请求顺序管理
- 依赖关系梳理:
- 在代码中对各个API调用进行梳理,明确哪些请求依赖其他请求的结果。可以通过绘制流程图或者在代码注释中清晰标记。
- 例如,假设有请求A和请求B,请求B依赖请求A的结果。在代码中:
async function fetchData() { const responseA = await axios.get('/api/a'); const responseB = await axios.post('/api/b', { data: responseA.data }); return { responseA, responseB }; }
- 队列管理:
- 使用JavaScript的
Promise
链式调用或者async/await
来确保请求按顺序执行。 - 对于复杂的依赖关系,可以将相关请求封装成函数,然后按照依赖顺序依次调用。例如:
async function fetchFirst() { return await axios.get('/api/first'); } async function fetchSecond() { const firstResponse = await fetchFirst(); return await axios.post('/api/second', { data: firstResponse.data }); }
- 在Qwik组件中,可以在合适的生命周期钩子中调用这些函数。比如在
onMount$
钩子中:
import { component$, onMount$ } from '@builder.io/qwik'; export default component$(() => { let result; onMount$(async () => { result = await fetchSecond(); }); return <div>{JSON.stringify(result)}</div>; });
- 使用JavaScript的
去重策略
- 基于缓存的去重:
- 创建一个缓存对象,用于存储已经请求过的API及其结果。
- 在发起请求前,先检查缓存中是否已经存在该请求。例如:
const requestCache = {}; async function axiosWithCache(url, config = {}) { if (requestCache[url]) { return requestCache[url]; } const response = await axios(url, config); requestCache[url] = response; return response; }
- 对于带参数的请求,需要将参数也纳入缓存的键值计算中。比如:
const requestCache = {}; async function axiosWithCache(url, config = {}) { const key = url + JSON.stringify(config.data); if (requestCache[key]) { return requestCache[key]; } const response = await axios(url, config); requestCache[key] = response; return response; }
- 防抖与节流:
- 如果是用户频繁触发的API请求(如搜索框的实时搜索),可以使用防抖或节流技术。
- 防抖:在一定时间内(例如300ms)如果再次触发相同请求,取消之前的请求并重新发起。可以使用
lodash
库中的debounce
函数。例如:
import debounce from 'lodash/debounce'; const searchInput = document.getElementById('searchInput'); const debouncedSearch = debounce(async () => { const searchTerm = searchInput.value; await axios.get('/api/search', { params: { term: searchTerm } }); }, 300); searchInput.addEventListener('input', debouncedSearch);
- 节流:在一定时间间隔内(例如500ms)只允许发起一次请求。同样可以使用
lodash
库中的throttle
函数。例如:
import throttle from 'lodash/throttle'; const scrollHandler = throttle(async () => { await axios.get('/api/scroll-data'); }, 500); window.addEventListener('scroll', scrollHandler);
错误处理
- 全局错误处理:
- 使用
axios
的interceptors
来设置全局的错误处理。例如:
axios.interceptors.response.use( response => response, error => { // 统一处理错误,如记录日志、显示错误提示等 console.error('API Error:', error); return Promise.reject(error); } );
- 使用
- 组件内错误处理:
- 在Qwik组件中,结合
try/catch
来处理特定请求的错误。例如:
import { component$, onMount$ } from '@builder.io/qwik'; export default component$(() => { let error; onMount$(async () => { try { await axios.get('/api/some-faulty-api'); } catch (e) { error = e; } }); return ( <div> {error && <p>Error: {error.message}</p>} </div> ); });
- 在Qwik组件中,结合
与Qwik的组件生命周期更好结合
- 请求在合适的生命周期发起:
onMount$
:用于发起只需要在组件挂载时执行一次的请求。例如:
import { component$, onMount$ } from '@builder.io/qwik'; export default component$(() => { let data; onMount$(async () => { const response = await axios.get('/api/initial-data'); data = response.data; }); return <div>{JSON.stringify(data)}</div>; });
onDestroy$
:如果有需要在组件卸载时清理的请求相关资源(如取消未完成的请求),可以在这个钩子中处理。例如:
import { component$, onMount$, onDestroy$ } from '@builder.io/qwik'; import axios from 'axios'; export default component$(() => { let cancelTokenSource = axios.CancelToken.source(); onMount$(async () => { try { const response = await axios.get('/api/data', { cancelToken: cancelTokenSource.token }); // 处理响应 } catch (e) { if (!axios.isCancel(e)) { console.error('Error:', e); } } }); onDestroy$(() => { cancelTokenSource.cancel('Component unmounted'); }); return <div>Component with API call</div>; });
- 响应数据更新组件状态:
- 当API请求成功返回数据后,及时更新Qwik组件的状态,以触发组件重新渲染。例如:
import { component$, signal$, onMount$ } from '@builder.io/qwik'; export default component$(() => { const data = signal$<any>(null); onMount$(async () => { const response = await axios.get('/api/data'); data.value = response.data; }); return <div>{JSON.stringify(data.value)}</div>; });