Post

[Day54] 웹 성능 + 비동기 처리 흐름

[Day54] 웹 성능 + 비동기 처리 흐름

신기하게도 바로 어제 포트폴리오 사용자 경험을 올리기 위해 Lighthouse를 사용해보았는데 오늘 수업에서 알려주셔서 스터디노트에서는 간단히 정리하고 자세한 성능 향상을 위해 수정할 내용은 따로 포스팅하려한다.

🔸 Lighthouse: 웹 성능 최적화 도구

  • Google에서 개발한 오픈소스 웹 성능 분석 도구
  • 웹사이트의 품질을 측정하고 개선할 수 있는 방법을 제공


  • 측정 영역: 성능, 접근성, PWA, SEO, 모범 사례
  • 점수 범위: 0~100점
  • 사용 목적: 웹사이트 품질 진단 및 개선

day53

주요 측정 영역

  1. 성능 (Performance)
    • 로딩 속도, 상호작용 지연 시간, 시각적 안정성 등
  2. 접근성 (Accessibility)
    • 장애인을 포함한 모든 사용자의 접근 가능성
  3. 모범 사례 (Best Practices)
    • 보안, 모바일 대응 등 웹 개발 표준 준수 여부
  4. SEO (검색 엔진 최적화)
    • 검색 엔진의 크롤링 및 인덱싱 용이성
  5. PWA (Progressive Web App)
    • 오프라인 지원, 설치 가능 등 PWA 요구사항 충족 여부

Lighthouse 활용 방법

1️⃣ 성능 최적화

지표개선 방법
First Contentful Paint(FCP)서버 응답 시간 단축, 렌더링 차단 리소스 제거
Largest Contentful Paint(LCP)이미지 최적화, 중요 리소스 우선 로드
Total Blocking Time(TBT)JS 실행 시간 단축, 코드 분할
Cumulative Layout Shift(CLS)이미지·광고 크기 명시, 레이아웃 안정화

2️⃣ 접근성 개선

  • 이미지에 alt 속성 추가
  • 텍스트 색상 대비 향상
  • 키보드만으로 탐색 가능하게
  • ARIA 속성 정확히 사용

3️⃣ SEO 최적화

  • <title>, <meta> 등 메타 태그 작성
  • 의미 있는 URL 구조
  • 모바일 대응
  • robots.txt, sitemap.xml 구현

⚠️ 주의사항

  • 점수는 테스트 환경(네트워크, 디바이스 등)에 따라 달라질 수 있음
  • 모든 항목을 무조건 따를 필요는 없음 (비즈니스 우선순위 고려)
  • 100점이 목표가 아니라 → 사용자 경험 개선이 진짜 목표!

🔸 JSON Server

  • JSON 파일을 기반으로 빠르게 RESTful API를 생성할 수 있는 도구
  • 프론트엔드 개발 시 빠른 프로토타입 구축 가능
  • 주요 특징:
    • JSON 파일을 데이터베이스로 사용
    • CRUD (GET, POST, PUT, PATCH, DELETE)
    • 필터링, 정렬, 페이지네이션 등의 기능 제공

설치 및 설정

  1. JSON Server와 개발 서버를 동시에 실행하기 위한 concurrently 패키지를 설치
1
npm install -D json-server concurrently
  1. package.json 스크립트 추가
1
2
3
4
5
"scripts": {
  "watch:json-server": "json-server db.json --port 3000",
  "watch:react": "react-scripts start",
  "dev": "concurrently npm:watch:*"
}

npm run dev : React + JSON Server 동시 실행

프로젝트 루트에 data 구성 (db.json)

1
2
3
4
{
  "products": [ /* 주얼리 상품들 */ ],
  "cart": []
}

데이터 조회

📌 조건 필터링 (쿼리 파라미터)

1
2
3
const response = await axios.get('http://localhost:3000/products', {
  params: { price_gte: 100000, category: 'top' }
});
조건의미
_lt미만 <
_lte이하 <=
_gt초과 >
_gte이상 >=
_ne같지 않음 !=
field_like=value포함 검색

📌 범위 지정

1
2
// 0번부터 2개 조회
fetchProducts('_start=0&_limit=2')
의미
_start시작 인덱스
_end종료 인덱스
_limit개수 제한

📌 페이지네이션

1
fetchProducts('_page=2&_per_page=2')

응답 정보 예:

1
2
3
4
5
{
  "pages": 3,
  "items": 6,
  "data": [ ... ]
}

📌 정렬

1
2
fetchProducts('_sort=discount')      // 오름차순
fetchProducts('_sort=-discount')     // 내림차순

🔸 비동기 통신

Axios를 사용하는 이유 (fetch vs axios)

항목fetchaxios
응답 형태JSON으로 변환 필요 (res.json())자동으로 객체 형태로 반환
요청 방식GET, POST만 자주 쓰고, 다른 메서드는 다소 불편PUT, PATCH, DELETE 등 다양한 요청 쉽게 가능
설정옵션을 매번 지정해야 함기본 설정과 인터셉터 등 유용한 기능 제공

📌 fetch는 응답을 받은 뒤 .json()으로 다시 파싱해야 하기 때문에 비동기 처리를 두 번 해야 함.
반면 axios는 한 번에 객체 형태로 받아오므로 간편함!

비동기 처리란?

  • 네트워크 요청 같은 시간이 오래 걸리는 작업을 백그라운드에서 실행하고
  • 그동안 다른 작업은 먼저 실행
  • 작업이 끝나면 나중에 결과를 가져오는 방식

ex) 백엔드에 데이터 요청 → 기다리는 동안 화면 렌더링 계속 → 응답 오면 그때 처리

Promise vs Async/Await

  • 예전엔 .then() 체이닝으로 처리 (Promise)
  • 지금은 async/await로 동기처럼 코드 작성 가능

await이 하는 일?

1
const data = await axios.get('/api')

결과가 올 때까지 기다린 후 다음 줄 실행
이전처럼 콜백 지옥이나 .then() 연속 사용 안 해도 됨!


자바스크립트 비동기 처리 흐름

자바스크립트는 싱글 스레드 언어임 -> 한 번에 한 가지 작업만

  • 하지만 비동기를 통해 시간이 오래 걸리는 작업동안 다른 작업을 계속할 수 있도록 만들어둠

day53

✅ Call Stack (콜 스택)

  • 현재 실행 중인 함수들이 쌓이는 공간
  • LIFO 구조 (Last In First Out, 후입선출)
  • 함수가 호출되면 스택에 들어가고, 실행이 끝나면 빠져나가

동기적인 작업은 여기서 모두 처리됨
ex) 함수1 → 함수2 → 함수3 이런 식으로 스택에 쌓였다 빠짐

✅ Web APIs

  • setTimeout, fetch, eventListener 등은 브라우저가 따로 처리
  • JavaScript는 “이 작업 좀 해줘!” 하고 브라우저한테 일을 던짐
  • 이건 비동기로 처리됨 → 결과가 준비될 때까지 기다릴 필요 X

ex) setTimeout(() => console.log('Hi'), 1000)
→ 브라우저가 1초 세고 나서 callback을 Task Queue에 넣어줘

⭐️⭐️⭐️

“비동기 함수는 Web API에서 따로 처리되고, 끝나면 Task Queue에 콜백이 등록된다. 콜스택이 비는 순간, 이벤트 루프가 Task Queue에서 콜백을 꺼내 실행시킨다.”


axios를 사용한 예시

await 안 썼을 경우

1
2
3
4
5
6
7
8
useEffect(() => {
  const getBannerData = () => {
    const data = axios.get('http://localhost:3000/banners/')
    console.log(data) // ❗ Promise 객체만 출력됨
    setBanner(data.data) // ❗ 아직 데이터가 안 들어와서 에러남
  }
  getBannerData()
}, [])

await/async 처리를 안하면 비동기로 돌기 때문에 콘솔에 Promise 객체만 찍힘 day53

await을 썼을 경우

1
2
3
4
5
6
7
8
useEffect(() => {
    const getBannerData = async () => {
        const data = await axios.get('http://localhost:3000/banners/')
        console.log(data)
        setBanner(data.data)
    }
    getBannerData()
}, [])

콘솔에 실제 데이터 출력

day53


예외 처리 (try-catch)

네트워크 요청은 실패할 수 있기 때문에 에러를 안전하게 처리해야 함

1
2
3
4
5
6
7
8
const getBannerData = async () => {
    try {
        const data = await axios.get('http://localhost:3000/banners/')
        setBanner(data.data)
    } catch (err) {
        console.log(err)
    }
}
  • try 블록에서 요청 시도해라 ~
  • 실패하면 catch로 넘어가 에러를 잡아라 !
  • 앱이 강제로 중단되지 않도록 도와주면서 무슨 에러인지 확인할 수 있음

API 분리 구조 (폴더 구조 예시)

1
2
3
4
5
6
7
8
9
10
11
12
src/
├── api/ <----------------------- API 호출 함수를 위한 디렉토리
│   ├── bannerApi.js <---------- 배너 관련 API 함수
│   └── productApi.js <------------ 상품 관련 API 함수
├── organism/
│   ├── Header.jsx
│   ├── Footer.jsx
├── layout/
│   ├── Default.jsx
├── pages/
│   ├── MainPage.jsx
│   └── ...

bannerApi.js

1
2
3
4
5
6
7
8
9
10
11
import axios from 'axios'
const BASE_URL = 'http://localhost:3000/banners/'

export const getBannerData = async () => {
  try {
    const res = await axios.get(`${BASE_URL}`)
    return res.data
  } catch (err) {
    console.log('err----', err)
  }
}

컴포넌트에서 사용 예시 (HeroSlider.jsx)

1
2
3
4
5
6
7
8
9
10
11
useEffect(() => {
  const fetchBanner = async () => {
    try {
      const data = await getBannerData()
      setBanner(data)
    } catch (err) {
      console.log('에러 발생:', err)
    }
  }
  fetchBanner()
}, [])

END

This post is licensed under CC BY 4.0 by the author.