# 웹 애플리케이션의 성능을 200% 끌어올리기 위한 코드 점검 및 개선 방법 ###### tags: `냥하` `강의` ## 프론트엔드 성능 ### 코드 바깥의 성능 :시간과 리소스 :clock1: :inbox_tray: - 시간: 초기 구동시간(파일 다운로드, 컨텐츠 렌더링, 인터랙션 가능), 계산 시간, 반응 시간 - 리소스: 자원 소모(CPU점유율, 메모리 스토리지, 네트워크 트래픽) 1. 시간 - 파일 다운로드: 1. (HTTP/1.1 기준) 최신 브라우저는 대체로 도메인 당 6개까지만 동시 처리 - 이미지, 동영상은 느린 업로드에 익숙하지만. 레이아웃이나 css가 느려지면 안좋게 보임 - 별도 도메인이나 CDN등으로 분산하는 것도 방법 2. 이미지는 최신 포멧 사용시 용량 절약 - WebP는 JPEG 파일의 평균 약 70% 정도 크기 - 레진 기술 블로그 참고 - ![image](https://user-images.githubusercontent.com/48500209/160038739-b2560c11-6ce4-47e6-9120-80d02180886a.png) 3. 화면 크기와 해상도에 따라 적절한 이미지 로딩 4. 웹 폰트 최적화 - 구글 폰트 - WOFF2는 WOFF, TTF에 비해 30% 용량이 작다. - 필요한 글자만 골라서 글꼴을 만들 수도 있다. 5. 화면 크기 등에 따라 필요한 스타일 시트만 로딩 6. `Link` 태그만으로도 접속 시간 절약 ``` link rel="dns-prefetch" link rel="preconnect" link rel="prefetch" ``` - 컨텐츠 렌더링, 인터랙션 가능 : 점진적으로 로딩되는 사이트가 훨씬 좋은 UX로 느껴짐 1. 로딩 속도 개선 - 필수 컨텐츠가 아니라면 비동기 로딩을 고려해보자(광고, 댓글, 헤더/푸더 등) - SPA는 덩치가 넘 크니까 비동기로 불러오는 경우가 좋다. - 이미지/아이프레임/스크립트 등은 필요할 때까지는 읽지 않는 게으른 로딩(Lazy loading) 기법을 고려해보자 ``` <img src="" loading="lazy"> ``` - 서버에서 불러올 때, 시간이 많이 걸린다면 플레이스 홀더 등으로 대체(로딩이 되고 있는 자리를 표시) - 계산 시간: 웹 워커, 느긋한 계산, 메모이제이션(계산 결과를 기억해두고 반복사용) - 1. 웹 워커: JS는 싱글 스레드이다. 하지만 멀티 스레드는 가능하다. HTML5의 워커 스레드 - 워커 스레드 - UI를 조작할 수 없다 - 워커 스레드 전용으로 분리된 파일이 필요하다 - postMessage()로 데이터를 전송하고, onmessage이벤트를 통해 받는 방식으로 통신한다. - 2. 느긋한 계산 - 3. 메모이제이션(계산 결과를 기억해두고 반복사용) - ex. 피보나치 계산, 순수함수임 항상 같은 값이 나오므로 기억해두고 사용하기 용이함 ### 애니메이션 성능 : 지나치게 느린 애니메이션 및 응답 속도는 사용자 경험을 저해한다. #### 반응 시간 1. 도허티 임계 2. 사용자는 UI가 100ms 이하로 반응해야 자신이 UI를 다루고있다고 느낀다. 3. 애니메이션은 60FPS를 기준으로 한다. 애니메이션 성능을 위해서는 가능하면 메인쓰레드에서 사용되는 것을 줄이고 컴포지터 쓰레드에서 진행될 수 있도록 한다. ![image](https://user-images.githubusercontent.com/48500209/160325768-0b3744b4-eb0f-4657-9cb9-d185f768bb61.png) *고성능 애니메이션을 위한 몇 가지 팁 1. 가능하면 JS보다는 CSS 애니메이션을 최대한 활용 2. 다음 CSS 속성위주로 애니메이션:: GPU 가속 적용(`transform`, `opacity`는 GPU가속이 자동 적용됨) ``` transform: translate or scale or rotate opacity ``` 3. 레이아웃 변경이나 리페인팅을 유발하는 CSS 속성은 비용이 많이 든다. - 레이아웃: width, height, padding, margin, display 등 - 페인트: color, background, outline, box-shadow 등 4. setTimeout보다는 requestAnivationFrame, Web Animations API 등 활용 - requestAnimationFrame: 브라우저가 최적화. 비활성 탭에서는 동작 안함 - Web Animations API: CSS애니메이션과 같은 애니메이션 엔진 사용 5. three.js, velocity.js와 같은 고성능 애니메이션 라이브러리 사용 6. will-change 속성(css속성)을 통해 브라우저가 최적화 할 속성 명시 - 남용하면 리소스 낭비, MDN에서는 최후의 수단으로 사용하라고 권고함 7. DOM 접근과 업데이트는 가능한 적게, 한 번에 몰아서 처리 - 엘리먼트 추가는 DocumentFragment 활용 -> 성능에 좋음 - before:: 그냥 바로 DOM 접근 ![image](https://user-images.githubusercontent.com/48500209/160347914-78671219-bc5c-4590-a7b8-440810b3499d.png) - after:: fragment만들어서 접근 -> fragment를 씌워서 추가해도 이 전 엘리먼트에 바로 추가됨.GOOD (cf, React fragment) ![image](https://user-images.githubusercontent.com/48500209/160348260-9e2f3723-a653-4242-92a8-2288dd789faf.png) ## Javascript 코드의 성능 : 자원소모, 리소스 리소스: CPU 점유율, 전력 소비량, 스토리지 용량, 메모리 누수, 네트워크 트래픽 사실 스크립트 언어는 자체적으로 관리해주는 것이 많아서 CPU(무한루프만 고려), 전력은 크게 신경 안써도 됨 1. 메모리 누수 : 프로그램이 필요하지 않은 메모리를 계속 점유하는 현상 C, C++ 언어와 달리 JS 엔진이 메모리 필요/불필요를 "추정"하여 해제(GC: Garbage Collection) -> 참조 카운팅 방식 사용 ``` // 참조 카운팅: 이 메모리에 있는 값을 몇 개의 변수(함수)가 참조하고있는지를 카운팅 // 값을 참조하고 있는 것이 없다면, 참고하고있는 것을 지움 var person ={ age:20 }; //age변수를 참조함 var other = person; person = null; other = null; ``` 참고: https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management - 메모리 생명주기: - **할당**(:사용할 메모리를 확보) -> **사용**(: 메모리 사용, 읽기, 쓰기) -> **해제**(불필요한 메모리 반환) ### 네트워크 트래픽 : 파일 용량을 줄이거나 필요할 때만 불러와서 트래픽 낭비를 줄인다. 1. 최소화한 JS, CSS 파일 사용 2. 프레임워크는 한 개 이하만 사용 3. 파일 주소의 파라미터는 주의해서 사용 - 의도하지 않은 캐시버스터(cache buster)가 될 수 있다. - 브라우저가 데이터의 변화가 없는데도 또 불러오는 일이 없도록 하자. - ![image](https://user-images.githubusercontent.com/48500209/160354793-86cf50e0-49d0-4e1a-b182-eb1119aef82f.png) 4. 이미지나 미디어는 필요할 때 불러오는 lazy loading을 활용하자 ## 요약 1. 브라우저가 읽어들일 용량을 줄여야한다 - 캐시, 게으른 로딩 2. JS 코드 실행이 느리면 로직 개선 및 최적화 기법을 도입해 볼 수 있다. - 게으른 계산, 메모이제이션 3. 자바스크립트도 멀티 스레드 프로그래밍이 가능하다. - 웹 워커 4. 사용자의 행동에는 100ms안에 반응을 보여야한다. 5. 애니메이션 성능의 기준은 60fps이다. 6. 너무 모든 걸 다 적용하려고 집착할 필요는 없다.