티스토리 뷰
🚀 개요
야놀자 X 패스트캠퍼스 프론트엔드 개발 부트캠프에서 이전 토스 클론 코딩하여 배포한 것을 멘토님과 피어리뷰를 통하여피드백을 받고 이를 리팩토링 할 시간과 기회를 얻게 됐다. 성능개선을 통한 최적화와 코드 가독성 측면으로 항상 관심이 있어서, PR과 주석을 통하여 웹 브라우저 렌더링 성능과 Indent가 중첩되어 사용한 것을 가독성이 보기 좋은 방법이 있는지에 대해 현직 FE개발자신 멘토님께 여쭤봤다.
아래에 멘토님과 동료님들의 피드백을 확인할 수 있다. 성능 측면에선 크게 두가지 피드백을 받았다.
1. 기존 scroll 이벤트들이 등록되다보니 메모리 누수가 발생할 가능성이 높고 성능 저하가 일어난다. => CSS나 JS 내장 애니메이션을 통하여 개선하는 것이 좋아보인다.
2. Opacity가 0 <=> 1로 바뀌는 부분에서 Reflow가 발생할 수 있다. Repaint와 Reflow 에 대해서 고민할 필요가 있다 => 브라우저의 렌더링 원리와 Opacity 와 관련된 링크 첨부
스스로 공부할 기회를 마련해 주셔서, 이와 관련되어 공부한 결과를 적고자 합니다. 우선 첫번째 피드백 부터 받아들여 JS의 내장 클래스인 Intersection Observer를 통하여 이벤트 핸들러를 제거하기로 합니다.
😵 이전 코드 및 설명
우선 기존의 코드는 스크롤을 할 때마다, 10개 정도의 스크롤 이벤트 핸들러의 콜백함수가 호출 됐으며, 각 콜백함수마다 요소의 getBoundingClientRect()(Reflow가 발생) 을 호출하였고, 이 값을 window.innerHeight 값과 비교하는 로직을 수행하였다. 이 상태에서 빠른 스크롤을 내리면, 수 백, 수 천번의 이벤트 콜백 함수들이 동기적으로 실행 되어 큰 성능 저하를 겪을 수 있다. 수 많은 스크롤 이벤트핸들러의 선언들은 성능저하를 불러 올 수 있다는 것이다.
또한 getBoundingClientRect() 실행 시 Reflow를 발생한다. Reflow는 렌더링 트리가 변경되어 레이아웃을 다시 잡고, 리페인트를 하는 과정을 뜻한다. Reflow는 Repaint에 비해 자원을 더 사용하므로, Reflow는 되도록 피하는 것이 좋다.
const homeText = document.querySelector('.home_text')
const homeIphone1 = document.querySelector('.home_image_container .iphone_wrap:first-of-type')
const homeIphone2 = document.querySelector('.home_image_container .iphone_wrap:last-of-type')
const homeText2 = document.querySelector('.home_text2')
// 스크롤 이벤트 등록
window.addEventListener('scroll', homeEventHandler)
const homeEventHandler = ()=>{
// homeTetxt요소의 맨 위로부터 뷰포트 상단까지의 길이 측정 및 화면에 나타났는지 감지
if(homeText.getBoundingClientRect().top < windowHeight-200){
// 애니메이션이 순차적으로 동작
setTimeout(()=>{
homeIphone1.style.opacity = 1
homeIphone1.style.animation = `appear_from_bottom ease 1.5s`
setTimeout(()=>{
homeIphone2.style.opacity = 1
homeIphone2.style.animation = `appear_from_bottom ease 1.5s`
setTimeout(()=>{
homeText2.style.opacity = 1
homeText2.style.animation = `appear_from_bottom ease 1.5s`
},600)
},600)
},600)
window.removeEventListener('scroll',homeEventHandler)
}
}
🧐 Intersection Observer 사용
Intersection Observer를 사용하면, 이 이벤트 핸들러의 콜백함수를 매 스크롤마다 동작하는 것이 아니라, 비동기식으로 관찰을 하여, Reflow를 발생시키지 않습니다.
new IntersectionObserver를 지정하여, 관찰을 하며, threshold 값을 통하여, 내가 원하는 요소가 화면에 등장했는지를 판단할 수 있습니다. (교차성,가시성을 계산)
😛 리팩토링 코드 및 설명
const homeText = document.querySelector('.home_text')
const homeIphone1 = document.querySelector('.home_image_container .iphone_wrap:first-of-type')
const homeIphone2 = document.querySelector('.home_image_container .iphone_wrap:last-of-type')
const homeText2 = document.querySelector('.home_text2')
// homeText가 50% 정도 뷰포트에 나왔을 경우 아래 콜백함수 실행
let observer1 = new IntersectionObserver(entries=>{
observer1cb(entries[0])
},{root: null,threshold:0.5})
// observer 콜백함수
const observer1cb = entry=>{
if(entry.isIntersecting){
homeText.style.opacity = 1
homeText.style.animation = `appear_from_bottom ease 1.5s`
// 애니메이션이 순차적으로 동작
setTimeout(()=>{
homeIphone1.style.opacity = 1
homeIphone1.style.animation = `appear_from_bottom ease 1.5s`
setTimeout(()=>{
homeIphone2.style.opacity = 1
homeIphone2.style.animation = `appear_from_bottom ease 1.5s`
setTimeout(()=>{
homeText2.style.opacity = 1
homeText2.style.animation = `appear_from_bottom ease 1.5s`
observer1.unobserve(homeText)
},600)
},600)
},600)
}
}
observer1.observe(homeText)
위와 같은 방법으로, Observer 객체에 IntersectionObserver 인스턴스를 할당하여, threshold 값을 지정한다. 특정 threshold값(화면에 나타나는 비율)에 도달할 경우 아래 observer 콜백 함수가 실행된다. 자세한 사용방법과 옵션에 대한 자료는 아래 참조란에 공식문서를 참조 바란다.
💡결론
ObserverIntersection JS 내장 클래스를 통하여, 동기적이며 초당 수천번씩 실행되어 메인 스레드에 악영향을 끼칠 수 있는 스크롤 이벤트를 비동기적이며, Reflow 또한 발생시키지 않아 효율적인 방식으로 리팩토링 할 수 있었다.
참조
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
#패스트캠퍼스 #부트캠프 #프론트엔드개발자 #국비지원취업 #국비지원
'웹 개발' 카테고리의 다른 글
[리팩토링/성능개선] 스켈레톤 UI 적용하기 JS과제 리팩토링 (0) | 2023.08.28 |
---|---|
[리팩토링 / 성능개선] Opacity변경에서의 Reflow의 발생 (2) | 2023.08.07 |
[HTML/CSS/Vanilla JS] 스크롤 애니메이션 (2) | 2023.07.27 |
[React TS + CSS] 클릭시 퍼지는 버튼 메뉴 만들기 (0) | 2023.02.12 |
[React + Typescript + Express + MySQL] 개발 환경 구축하기[1] (0) | 2022.08.19 |
- Total
- Today
- Yesterday
- FE 주니어
- 모노레포
- 성능 개선
- Not Working
- 깃허브
- Vercel
- 이미지최적화
- FE
- 개발자 회고
- 사이드프로젝트
- 성능 측정
- ci/cd
- 로딩성능
- 부트캠프
- no found
- RARS
- netlify
- next 14
- 깃허브 사용법
- 프론트엔드개발자
- kpt
- 프론트엔드 성능
- 인프콘 2023
- Tailwind CSS
- Github Actions
- 패스트캠퍼스
- 국비지원
- 국비지원취업
- 리뷰
- JavaScript
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |