面试题答案
一键面试1. 抽象为独立模块
- 自定义 Stores:将通用的自定义 stores 逻辑提取到独立的 JavaScript 模块中。例如,如果有一个用于管理用户登录状态的 store,可在
userStore.js
中定义:
import { writable } from'svelte/store';
export const userStore = writable({ isLoggedIn: false, userInfo: null });
然后在各个 Svelte 组件中导入使用:
<script>
import { userStore } from './userStore.js';
</script>
- 自定义 Actions:同样,将自定义 actions 提取到独立模块。比如一个用于防抖的 action,在
debounceAction.js
中:
export function debounce(node, delay) {
let timer;
const handleEvent = (event) => {
clearTimeout(timer);
timer = setTimeout(() => {
node.dispatchEvent(new CustomEvent('debounced', { detail: event }));
}, delay);
};
node.addEventListener('input', handleEvent);
return {
destroy() {
node.removeEventListener('input', handleEvent);
}
};
}
在组件中导入:
<script>
import { debounce } from './debounceAction.js';
</script>
<input use:debounce={300}>
2. 使用 Svelte Stores 的衍生模式
- 对于复杂的自定义 stores,可通过衍生(derived)来创建新的 stores,减少重复计算。例如,有一个存储购物车商品列表的 store,以及一个计算总价格的衍生 store:
import { writable, derived } from'svelte/store';
const cartItems = writable([]);
const totalPrice = derived(cartItems, ($cartItems) => {
return $cartItems.reduce((acc, item) => acc + item.price * item.quantity, 0);
});
这样,只有当 cartItems
变化时,totalPrice
才会重新计算,提高性能。
3. 利用 Svelte 组件的生命周期管理
- 在组件使用自定义 stores 或 actions 时,合理利用生命周期函数。例如,当组件销毁时,清理与自定义 action 相关的定时器或事件监听器。
<script>
import { onDestroy } from'svelte';
let timer;
function startTimer() {
timer = setInterval(() => {
// 执行逻辑
}, 1000);
}
startTimer();
onDestroy(() => {
clearInterval(timer);
});
</script>
对于自定义 stores,可在组件销毁时,取消订阅(如果需要),以避免内存泄漏。
4. 优化数据传递
- Props 传递:在组件间传递数据时,避免传递不必要的 props。只传递组件真正需要的数据,减少组件重新渲染的频率。
- Context API:对于多层嵌套组件间共享数据,使用 Svelte 的 Context API(
setContext
和getContext
)。这比通过 props 层层传递数据更高效和易于维护。例如,在父组件中:
<script>
import { setContext } from'svelte';
const sharedData = { value: 'Some shared value' };
setContext('sharedDataContext', sharedData);
</script>
在深层子组件中:
<script>
import { getContext } from'svelte';
const sharedData = getContext('sharedDataContext');
</script>
5. 代码拆分与懒加载
- 对于大型应用,将复杂的自定义逻辑拆分成更小的代码块,并进行懒加载。例如,对于不常用的自定义 stores 或 actions 相关的功能,可使用动态导入:
<script>
let myAction;
const loadAction = async () => {
const { myCustomAction } = await import('./myAction.js');
myAction = myCustomAction;
};
loadAction();
</script>
<button use:myAction>Button with action</button>
这样可以减少初始加载时间,提高应用性能。
6. 测试与文档
- 单元测试:对自定义 stores 和 actions 进行单元测试,确保其功能正确。使用测试框架如 Vitest 来测试 stores 的状态变化和 actions 的行为。例如,测试一个自定义 store 的更新逻辑:
import { describe, it, expect } from 'vitest';
import { myCustomStore } from './myStore.js';
describe('myCustomStore', () => {
it('should update correctly', () => {
myCustomStore.update((state) => {
state.value++;
return state;
});
expect(myCustomStore.get().value).toBe(1);
});
});
- 文档:为自定义 stores 和 actions 编写详细文档,说明其功能、使用方法、输入输出等。这有助于其他开发者理解和维护代码,例如在
myAction.js
文件头部添加注释:
/**
* 防抖 action
* @param {HTMLElement} node - 应用该 action 的 DOM 节点
* @param {number} delay - 防抖延迟时间(毫秒)
* @returns {Object} - 包含销毁函数的对象
*/
export function debounce(node, delay) {
// 函数实现
}