Medium - How to improve JavaScript Performance
in Trend
Trend 파악을 위한 Medium 기고문 포스팅 - 자바스크립트 성능을 향상 시키는 법; 똑같은 일을 더욱 효율적으로 하는 팁들,
지난 몇년간 자바스크립트는 스크립트 언어의 선두주자가 되었고 가장 많은 개발자들이 사용하는 언어가 되었습니다. 자바스크립트는 서버와 클라이언트 양쪽에서 모두 쓰입니다. 그리고 깃허브에서 가장 인기가 많은 언어 중에 하나죠.
First comes Detecting Problems
Lighthouse 는 웹페이지에서 널리 쓰이는 도구입니다. 접근성을 도와주고 audit 성능, SEO, 그리고 많은 best practice들이 있습니다. 비슷한 도구로 Google PageSpeed 가 있는데 자바스크립트 개발자들에게 웹사이트의 성능을 영역별로 개선시킬 수 있도록 도와줍니다.
크롬의 메인 메뉴에 옵션에 보면 More Tools 항목이 있고 해당 메뉴에서 메모리와 CPU 사용량을 볼 수 있습니다. 자세한 분석을 보고 싶다면 크롬이나 파이어폭스의 퍼포먼스 뷰를 사용할 수도 있습니다. 이런 것들을 사용하면 다양한 지표들을 뽑을 수 있습니다.
더욱 깊게 파고 들어가보길 원하시는 분들은 Navigation Timing API를 사용해 보세요. 웹사이트의 성능을 측정하는데 사용할 수 있는 데이터를 제공해 줍니다.
Variables Scope
우리가 특정 함수를 호출할 때마다 함수에서 사용되는 변수들이 내부적으로 저장됩니다. 변수들은 크게 2가지 타입으로 나눌 수 있습니다.
- 지역 변수: 지역변수는 선언된 스코프에서만 사용할 수 있습니다.
- 전역 변수: 전역 변수는 스크립트 전체에서 사용됩니다.
함수 호출에서 자바스크립트 컴파일러는 사용될 변수의 스코프를 찾아봅니다. 스코프 체인의 수가 많아지 수록 현재 영역 외부에 있는 변수에 접근하는데 시간이 많이 걸리게 됩니다. 이것이 바로 엔진에서 지역변수보다 전역변수에 접근할 때 시간이 더 오래 걸리는 이유입니다. 따라서 거의 변수를 지역적으로 사용신다면 변수에 접근하는데 필요한 시간이 매우 감소될 것입니다. 결과적으로 응용프로그램 전체에 속도를 향상 시킬 것입니다.
Code Light and Small
모바일 응용프로그램에서 높은 성능을 유지하기 위해서는 코드를 될 수 있는한 가볍고 컴팩트하게 만들어야 합니다. 결과적으로 이것은 페이지 지연 시간을 줄여줄 것이고 스피드를 향상 시켜줄 것입니다. 모듈을 작성하면서 아래와 같은 질문을 스스로 하신적이 있나요?
정말 이 모듈이 필요한가?
내가 이 프레임워크를 사용하는 이유는 무엇인가?
오버헤드를 감수할 만큼 꼭 필요한 작업인가?
만약 그렇다면 이것이 가장 간단한 방법인가?
응용프로그램의 성능을 향상시키는 또 다른 방법은 분산되어 있는 JS 파일을 하나로 통합하는 것입니다. 예를 들어 앱이 7개의 자바스크리브 파일이 있다면 브라우저는 7개의 다른 HTTP 요청을 통해서 그것들을 모두 fetch 해야 할 것입니다. 이런 상황을 피하기 위해서는 7개의 파일을 그냥 하나에 통합하는 것입니다.
Avoid Unwanted Loops
자바스크립트에서 반복문을 사용하는 것은 브라우저 단에서 너무 많은 일을 하게 되기 때문에 좋지 않습니다. 루프 내의 코드는 최대한 짧아야 합니다. 루프 내에 작업을 줄일 수록 루프는 빨라지겠죠. 게다가 몇가지 트릭을 적용할 수도 있습니다. 예를 들어 루프를 순회하며 길이를 체크하는 것이 아니라 배열의 길이를 다른 변수에 저장해 두는 것이죠. 이것은 장기적인 관점에서 코드를 최적화 하는 것이며 더욱 효과적인 방식으로 동작하게 하는 것입니다.
Minimize DOM access
자바스크립트 네이티브 환경에서 벗어난 곳에서 이뤄지는 모든 순회는 심각한 퍼포먼스 저하를 일으키고 예측성이 떨어집니다. 예를들어 호스트 브라우저가 외부 환경의 DOM 객체와 여러번 인터렉트 한다면 브라우저를 새로고침할 때마다 매번 성능에 영향을 줄 것입니다. 이것을 최소화 하기 위해서 DOM 접근을 최소화 해야 합니다. 이것을 달성하기 위한 방법이 몇가지 있는데 레퍼런스들을 브라우저 객체에 저장하거나 전체적인 DOM의 경로를 줄이는 것입니다.
Asynchronous Programming
응용 프로그램에서 우리는 여러개의 내부 API를 호출하여 데이터를 처리합니다. 이 방법 중에 하나는 분리된 미들웨어 장치를 가지고서 각각 기능을 활용하는 것이죠. 그러나 자바스크립트는 싱글 쓰레드이며 많은 동기화 컴포넌트 들이 있습니다. 이런 컴포넌트들은 응용프로그램을 멈추게 할 가능성도 있죠.
이런 상황을 해결하기 위해서 위의 그림처럼 자바스크립트의 비동기화 기능이 필요한 것입니다. 비동기화 코드를 효과적으로 관리할 수 있게 해줍니다. 비동기화 코드는 이벤트큐에 푸시되어 다른 코드들이 실행이 된 이후에 수행이 됩니다. 그러나 자바스크립트의 비동기화 기능이어도 외부 라이브러리를 사용한다면 그것이 동기화 블록킹 콜처럼 동작할 수도 있습니다. 이것또한 응용프로그램 전체의 퍼포먼스에 영향을 줍니다.
따라서 가장 좋은 방법은 항상 비동기화 API들을 코드에 사용해야 합니다. 다만 처음 사용하는 사람들에게는 비동기화 코드가 좀 어렵게 느껴질 수도 있겠네요.
Event Delegation
단일 이벤트 핸들러로 여러개의 이벤트를 효과적으로 처리할 수 있는 방법은 이벤트 델리게이션을 사용해서 전체 페이지의 이벤트 타입을 효과적으로 관리하는 것입니다. 우리가 이벤트 대표자를 사용하지 않고 여러개의 이벤트 핸들러를 달아놓으면 큰 웹 응용프로그램의 성능은 급격히 나빠질 것이고 응용프로그램을 멈추게 할 수도 있습니다.
이벤트 델리게이션은 다음과 같은 장점이 있습니다.
- 관리 측면에서 공수가 적다
- 실행에 요구되는 메모리가 적다
- 돔과 다른 코드들을 비롯하여 결합도를 낮춰준다
Gzip compression
Gzip은 가장 많은 클라이언트와 서버에서 압축/압축풀기를 위해 사용하는 소프트웨어 입니다. 브라우저가 자원에 압축을 요청하면 서버는 브라우저로 보내기 전에 압축을 할 것입니다. Gzip은 큰 자바스크립트 파일을 압축하여 대역폭을 줄이기 때문에 지연속도를 줄이고 응용프로그램 전체의 성능을 강화시킵니다.
Boost performance by caching object
ㅋ캐싱은 자주 접근되는 데이터를 일시적으로 캐시에 저장해서 다른 하위 요청에 재사용 하는 것입니다. 이런 캐싱은 여러분의 서버가 쉽게 적재할 수 있도록 도와줍니다. 여러개의 요청을 복사해서 다음에 같은 요청이 들어오면 캐시를 검사하고 전달하는 것이죠. 카피가 없다면 요청은 서버에 전달되고 컴파일 및 수행될 것이고 요청의 복사본은 캐시에 저장됩니다.
두가지 방식으로 이것을 구현할 수 있습니다. 하나는 HTTP 프로토콜 캐시이고 다른 것은 자바스크립트 캐시 API를 사용하는 것입니다. 이것은 서비스 워커 설치를 통해 사용할 수 있습니다. 반복해서 접근하는 객체를 사용자 정의 변수에 저장하거나 캐시 객체를 조회해서 변수를 사용하는 것으로 엄청나게 성능을 향상 시킬 수 있습니다.
Limiting memory Usage
메모리 사용 제한은 자바스크립트 개발자들이 반드시 가져야할 주요 기술입니다. 응용프로그램이 실행되는 디바이스에서 요구되는 정확한 메모리를 판별하는 것이 매우 어렵기 때문이죠.
만약 응용프로그램이 브라우저를 위해 새로운 메모리 리저브를 요청했다면 브라우저의 가비지 컬렉터가 놀고있는 메모리를 찾아서 해제시킬 것입니다. 자바스크립트 코드는 메모리가 거기서 해제될 때까지 기다리게 되겠죠. 이런 일이 지속적으로 일어난다면 페이지가 느려질 수 밖에 없습니다.
Delay loading of javaScript
명백히 사용자들이 원하는 것은 빠른 로딩속도 입니다. 그러나 모든 함수들이 페이지 초기화면에서 모두 로딩되어야 하는 것은 아니죠. 사용자들이 클릭과 탭 전환같은 기능을 수행하는 경우에 초기화면에서는 해당 함수들이 로딩 되었을 때 로딩이 완료되었다고 할 수 있습니다. 이 방법은 초기화면에서 모든 자바스크립트 코드 컴파일과 로딩을 피할 수 있게 해줍니다. 페이지가 로딩이 되고 난 후에 사용자가 나중에 사용할 함수들을 그 때 로딩하는 것입니다. 구글의 RAIL 모델에 따르면 우리는 로딩을 위한 블록을 50ms이내로 해야합니다. 이것이 페이지에서 사용자 인터렉션에 영향을 주는 것을 방지할 수 있습니다.
NO Memory Leaks
메모리 누수와 같은 경우 페이지는 점점 더 많은 메모리를 차지하게 되어 결국에는 장치의 모든 메모리를 끌어다 쓸 것입니다. 이것또한 전체적인 성능에 영향을 미치게 되죠.
메모리 릭 문제를 측정할 수 있는 도구들이 있습니다. 크롬 개발자 도구에서 성능 탭을 보시면 타임라인에 기록을 하고 있습니다. 대개 페이지에서 제거된 돔 조각들이 메모리 누수를 일으키며 이것은 참조되는 변수들이 가바지 컬렉터가 걔네들을 없애버리는 걸 막기 때문입니다.
Use Various Optimizations
데이터 구조 최적화와 관련된 작업을 해결하기 위해서는 항상 제일 작은 컴퓨팅 시간이 걸리는 알고리즘을 사용해야 합니다.
- 특정 키에 대한 값을 가져올 때는 스위치문이나 케이스 구문을 사용하지 말고 배열을 사용해서 값을 찾도록 하세요.
- 적은 연산으로 동일한 결과를 얻도록 알고리즘을 다시 짜세요
- 재귀호출을 피하십쇼
- 모든 반복되는 함수에 연산과 호출과 변수를 넣으세요
- 조건문을 만들 때는 참인 결과가 주로 되게 만들어야 프로세서 실행 관점에서 좋습니다.
Summary
- 먼저 성능 체크 툴을 사용해서 문제를 파악하는 것이 먼저다.
- 지역변수를 많이 사용하는게 좋다. 전역변수 같은 것은 스코프 체인을 타고 감으로 접근 시간이 오래걸린다.
- 크롬 개발자 도구로 메모리 누수 체크를 할 수 있다. 주로 페이지에서 삭제된 돔이 메모리에 남아있는 경우가 많다.
- 항상 비동기화 함수를 사용하자. 자바스크립트는 싱글 스레드이기 때문에 동기화 코드는 심각한 성능 저하를 가져온다.
- 요청에 대하서 캐시를 사용하면 성능이 엄청 향상된다. 요청을 캐시에 저장해두고 동일한 요청이 오면 저장된 것을 꺼내서 보낸다.
- 이벤트 델리게이션을 사용해야 한다. 여러개의 이벤트 핸들러를 달면 성능이 느려진다.
- 루프 내의 작업은 항상 최소화 해야한다.