웹 인터페이스의 반응성을 개선하는 것은 종종 프론트엔드가 백엔드와 통신하는 방식을 최적화하는 것에서 시작됩니다. Vue.js 기반의 Semaphore UI에서는 사용자에게 데이터 로딩을 더 빠르고 부드럽게 만들기 위해 여러 가지 기술을 도입했습니다. 이 포스트에서는 버전 2.14에서 구현한 세 가지 가장 영향력 있는 변경 사항을 공유합니다.
API 사용 최적화의 이유
API는 동적 웹 앱의 중추 역할을 하지만, 잘 관리되지 않은 요청은 병목 현상을 초래할 수 있습니다. 순차 호출에 대한 긴 대기 시간이나 중복 데이터 가져오기는 사용자 경험을 저하시킵니다. 이러한 문제를 정면으로 해결해 보겠습니다.
1. Promise.all()
을 사용한 병렬 요청
문제: 순차 요청
일반적인 함정은 API 호출을 하나씩 하는 것입니다. 예를 들어, 사용자 세부 정보를 가져온 다음, 그들의 주문, 그들의 선호도를 가져오는 경우입니다:
// 순차적 접근 (느림 😞)
async function fetchData() {
const user = await getUser();
const inventory = await getInventory(projectID);
const templates = await getTemplates(projectID);
return { user, inventory, templates };
}
여기서 각 요청은 이전 요청이 완료될 때까지 기다립니다. 각 호출이 200ms가 걸린다면, 총 시간은 600ms—상당한 지연입니다.
해결책: 병렬 실행
Vue.js는 JavaScript의 비동기 기능을 활용하므로 Promise.all()
을 사용하여 여러 요청을 동시에 실행할 수 있습니다:
// 병렬 접근 (빠름 ⚡)
async function fetchDataParallel() {
const [user, inventory, templates] = await Promise.all([
getUser(),
getInventory(projectID),
getTemplates(projectID),
]);
return { user, inventory, templates };
}
독립적인 요청을 그룹화함으로써 세 가지 호출이 동시에 해결됩니다. 각 호출이 200ms가 걸린다면, 총 시간은 200ms로 줄어듭니다!
Vue와 통합
Vue 컴포넌트에서 이 패턴을 생명주기 훅이나 메서드에서 사용하세요:
export default {
props: {
projectID: Number,
},
watch: {
async projectID() {
await this.fetchDataParallel();
},
},
async created() {
await this.fetchDataParallel();
},
methods: {
async fetchDataParallel() {
try {
const [
this.user,
this.inventory,
this.templates
] = await Promise.all([
getUser(),
getInventory(this.projectID),
getTemplates(this.projectID),
]);
} catch (error) {
console.error("데이터 로딩 실패:", error);
}
};
}
팁: 데이터가 로드되는 동안 사용자를 참여시키기 위해 스켈레톤 로더와 결합하세요.
2. 캐시된 API 응답 재사용
문제: 중복 가져오기
앱은 종종 여러 컴포넌트에서 동일한 데이터를 다시 가져옵니다(예: 여러 뷰에서 요청된 사용자 프로필 데이터). 이는 대역폭을 낭비하고 인터페이스를 느리게 만듭니다.
해결책: 캐시 및 재사용
API 응답을 저장하고 무효화될 때까지 재사용합니다. Vue의 반응성 시스템은 중앙 집중식 스토어(예: Pinia 또는 Vuex)를 사용하여 이를 쉽게 만듭니다:
1단계: 캐시 스토어 생성
// stores/apiCache.js
import { defineStore } from 'pinia';
export const useApiCache = defineStore('apiCache', {
state: () => ({
project: null,
templates: {},
}),
actions: {
async fetchProject() {
if (!this.project) {
this.project = await getProject();
}
return this.project;
},
async fetchTemplates(id) {
if (!this.templates[id]) {
this.templates[id] = await fetchTemplates(id);
}
return this.templates[id];
},
},
});
2단계: 컴포넌트에서 스토어 사용
// Component.vue
import { useApiCache } from '@/stores/apiCache';
export default {
setup() {
const apiCache = useApiCache();
// 캐시된 사용자 재사용 또는 한 번만 가져오기
const user = apiCache.fetchUser();
return { user };
},
};
팁: Semaphore UI에서는 아직 Pinia를 사용하지 않지만, 곧 마이그레이션할 계획입니다.
캐시 무효화 전략
- 시간 기반 만료: 설정된 기간 후에 캐시된 데이터를 삭제합니다.
- 수동 트리거: 변형 후 무효화합니다(예: 사용자가 프로필을 업데이트할 때).
- Vue의 반응성: 앱의 상태가 변경될 때(예: 로그아웃 시) 데이터를 재설정합니다.
3. 부드러운 전환을 위한 스켈레톤 로더 사용
문제: 로딩 중 비응답 UI
최적화된 API 호출이 있더라도, 사용자는 데이터가 로드되는 동안 짧은 지연을 경험합니다. 이 시간 동안 빈 화면이나 멈춘 인터페이스는 실제 가져오기 시간이 최소화되더라도 앱이 다듬어지지 않았거나 느리게 느껴질 수 있습니다.
해결책: 스켈레톤 로더
스켈레톤 플레이스홀더는 데이터가 로드되는 동안 콘텐츠의 레이아웃을 모방하여 시각적 피드백을 제공하고 사용자의 참여를 유지합니다. 병렬 요청 및 캐싱과 결합하면 속도의 지각을 원활하게 만듭니다.
Vue.js에서 스켈레톤 로더 추가 방법
1단계: 스켈레톤 컴포넌트 선택
Semaphore UI에서는 Vuetify 프레임워크를 사용합니다. 이 프레임워크는 이미 스켈레톤 로더 컴포넌트를 포함하고 있습니다.
<v-skeleton-loader
type="
table-heading,
image,
list-item-two-line,
list-item-two-line,
list-item-two-line"
></v-skeleton-loader>
2단계: 비동기 데이터 가져오기와 통합 로딩 상태를 사용하여 스켈레톤과 실제 콘텐츠 간에 전환합니다:
// Component.vue
export default {
data() {
return {
isLoading: true,
user: null,
templates: [],
};
},
async created() {
this.isLoading = true;
try {
[this.user, this.templates] = await Promise.all([
fetchUser(),
fetchTemplates(),
]);
} finally {
this.isLoading = false;
}
},
};
3단계: 스켈레톤 조건부 렌더링
<template>
<div class="user-profile">
<v-skeleton-loader
v-if="isLoading"
type="
table-heading,
image,
list-item-two-line,
list-item-two-line,
list-item-two-line"
></v-skeleton-loader>
<v-card v-else>
<h2>{{ user.name }}</h2>
<v-card v-for="tpl in templates" :key="tpl.id">
<v-card-title>{{ tpl.name }}</v-card-title>
<v-card-text>{{ tpl.description }}</v-card-text>
</v-card>
</v-card>
</div>
</template>
로더 디자인을 위한 고급 팁
- 콘텐츠 구조 일치: 스켈레톤을 실제 레이아웃(예: 이미지 플레이스홀더, 텍스트 라인)에 맞게 디자인합니다.
- 위치 우선 콘텐츠: 배경 데이터가 완료되는 동안 보이는 콘텐츠에 대한 로더를 먼저 표시합니다.
- 캐싱과 결합: 캐시된 데이터가 존재하는 경우, 스켈레톤을 건너뛰고 즉시 데이터를 표시합니다.
이것이 중요한 이유
- 사용자 경험: 74%의 사용자가 로드 시간을 인식합니다 (PWA Stats).
- 지각 성능: 로더는 대기 시간을 15-30% 더 짧게 느끼게 합니다 (NNGroup Research).
- 브랜드 신뢰: 다듬어진 전환은 전문성을 신호합니다.
모든 것을 종합하기
병렬 요청, 스마트 캐싱, 스켈레톤 로더를 결합함으로써 우리는 상당한 개선을 이룰 수 있었습니다:
- 더 빠른 초기 로드: 병렬 요청이 데이터 로드 시간을 크게 단축했습니다.
- 부드러운 탐색: 재사용된 응답이 중복 네트워크 호출을 줄였습니다.
- 향상된 사용자 참여: 스켈레톤 로더가 시각적 피드백과 지각된 속도를 개선했습니다.
API 사용 최적화는 단순한 성능 향상뿐만 아니라 사용자 경험을 개선하는 것입니다. 우리는 Semaphore UI를 더 빠르고 친근하게 만들기 위해 매 업데이트마다 프론트엔드를 계속 다듬어 나갈 것입니다.