NOMO.asia

FLO 뮤직 웹의 속도가 느린 이유??

Posted 2019. 9. 5. 22:35, Filed under: 개발/JavaScript

FLO 뮤직을 사용한지 대충 3개월정도 되었는데, 이 서비스는 분명한 장단점이 있다. FLO 뮤직의 좋은 점으로는 PC로 이용할 때 별도의 프로그램 설치 없이 웹기반으로 이용할 수 있다는 점, 그리고 추천 음악 리스트가 꽤 괜찮다는 점이 있다.

그렇지만 속도와 편의성 면에 있어서 불편점이 꽤 많았다. 전체적인 동작 속도가 느렸고, 각 메뉴를 이동하는데 꽤 오랜 시간이 걸렸으며, 어떤 동작을 실행하려고 할 때 잠깐 먹통이 되는 경우가 잦았다. 그리고 편의성 면에서 불편한 것이 엄청 많았다. 특히 플레이리스트가 마음에 안 드는데, 한 곡을 표시하는 높이가 너무 두꺼워서 한 화면에 많은 곡을 보기가 힘들었고, 플레이리스트에 등록된 곡을 삭제하려면 매번 편집 메뉴로 들어가야 한다는 점이 불편했다. 또, 추천 음악 리스트를 구독할 때 내가 싫어하는 곡이 섞일 수가 있는데 이런 곡을 필터링 할 수 있는 기능이 없다는 것이 아쉬웠다.

그래서 나는 최근에 이러한 불편함을 개선하는 UserScript 기능을 만들고자 하였고, 플레이리스트에서 한 곡을 표시하는 높이를 조절하는 것은 CSS 수정만으로도 쉽게 가능한 것이라 크게 어려운 것은 아니었다. 그런데 편집 모드로 들어가지 않아도 리스트에서 곡을 바로 삭제할 수 있도록 하는 기능을 위해 웹사이트의 버튼에 연결된 이벤트의 자바스크립트 코드를 보던 도중 이 웹사이트의 이상한 점을 발견하게 되었다.

문제 증상

FLO 뮤직을 써본 사람은 알겠지만, 플레이리스트에서 편집 버튼을 누른 직후에 마우스 휠을 아무리 굴려도 스크롤이 움직이지 않는 시간, 즉 웹사이트가 잠깐 멈추는 시간이 존재한다. 이렇게 먹통이 되는 시간은 플레이리스트에 등록된 곡 수가 늘어날 수록 증가한다.

플레이리스트에는 최대 3000곡까지의 곡을 등록할 수 있는데, 리스트에 등록된 곡 수가 1000곡이 넘어가면 편집 버튼을 누르고 짧게는 3~4초 이상 지난 후에야 스크롤이 움직이기 시작한다. 그런데 100곡 미만의 곡을 플레이리스트에 등록해두면 먹통이 된다는 느낌을 받기 힘들다.

내 PC는 CPU i7-6700K, 1TB SSD, 32GB RAM 이라는, 나름 고사양의 축에 드는 PC이므로 PC 사양 때문에 문제가 발생할 일은 없다.

플레이리스트에 등록된 곡 리스트는 로컬 스토리지에 저장되기 때문에 별도로 편집/완료 로그를 남기는 것 외에 서버와 통신을 하지는 않고, 일어나는 동작이라고는 그냥 로컬 스토리지를 읽거나 지우고, 엘리먼트를 생성하고 없애는 동작으로 추정되기 때문에 그리 비용이 많이 드는 작업이라고 생각되지도 않는다.

또한 플레이리스트에 있는 곡 수가 많으면 플레이리스트와 직접적으로 무관한 다른 동작까지 느려진다.

왜 이런 문제가 생기는 것일까?

FLO 뮤직 웹의 속도가 느린 이유 추정

내가 전문적인 웹개발자는 아니지만 대충 이유를 추정해보자면 Vue 로 코드를 작성할 때 플레이리스트가 나름 큰 규모의 dynamic list 라는 점을 고려하지 않아서 인 것 같다.

FLO 뮤직 웹은 플레이리스트 내 거의 모든 버튼에 이벤트 위임(event delegation)을 사용하지 않고, 각 엘리먼트가 "동적으로 생성될 때마다" 엘리먼트 하나하나에 이벤트를 직접 등록(direct event)하고 있었다. 그리고 Vue를 사용하고 있으므로, 이러한 이벤트 등록은 Vue에 의해서 자동으로 이루어지는 것으로 추정된다.

이벤트 위임이란, 아래와 같이 이벤트를 등록하는 방식을 말한다.

$(document).on("click", "span.btn.delete", function(){console.log("delete 버튼 클릭됨")});

각 엘리먼트가 생성될 때마다 직접 이벤트를 등록하려면 엘리먼트 하나하나마다 아래와 같이 하면 된다.

$(`<span class="btn delete">삭제</span>`).on("click", function(){console.log("delete 버튼 클릭됨")}).appendTo(...

물론 FLO 뮤직 웹이 jQuery 를 사용하고 있지는 않으며, Vue 를 이용해 작성된 코드라서 실제 코드를 위와 같이 작성하지는 않았겠지만 대충 예시를 든 것이다.

이벤트 위임은 실제 이벤트가 동작할 때 직접 엘리먼트에 이벤트를 등록했을 때보다 반응이 아주 조금 느리다는 단점은 있지만, 동일 동작을 하는 다수의 이벤트를 등록하는 경우에 단 한 번의 이벤트 등록만으로 해결되므로 이벤트 등록 시 속도와 메모리 관점에서 좋은 퍼포먼스를 보인다고 한다.

이벤트 위임을 안 하고 그냥 이벤트를 등록한게 뭐가 문제야? 라고 할 수 있겠지만, 플레이리스트에 곡 하나가 추가되면 웹사이트 초기 로딩 시 약 16개의 이벤트가 추가로 등록되는 것을 확인했다. 1000곡이면 16000개, 2000곡이면 32000개, 3000곡이면 48000개의 이벤트가 등록되는 셈이다.

리스트에 약 700곡이 등록되어 있을 때, 이벤트가 등록될 때마다 console 창에 메시지를 찍도록 했는데 아래 그림에서처럼 순식간에 12000건을 넘겼다.

그리고, 편집/완료 버튼을 누를 때마다 버튼에 해당하는 엘리먼트 생성/삭제, 이벤트 등록/해제를 반복하고 있었다. 그것도 플레이리스트에 등록된 전체 곡에 대하여 이런 동작을 하고 있었다. lazyload 처럼 실제 유저가 접근 가능한 범위에 대해서만 이런 동작을 해도 먹통이 되는 일은 없을텐데...

FLO 뮤직 웹사이트에서 몇몇 이벤트를 무력화하여 일부 이벤트만 남긴 뒤 동작 시간을 체크하는 퍼포먼스 테스트를 해보다가 분석할 능력도 없고 내가 지금 바쁜데 뭘하고 있나 싶어서 접었다. 대충 추정을 해보자면 리스트에 1000곡이 등록되었을 때, 1000개의 엘리먼트와(각 리스트가 하위 요소를 가지고 있기는 하지만) 16000개 정도의 이벤트 수가 엄~청 많게 느껴지지는 않지만, Vue 와 같은 반응형 시스템의 렌더러를 거치는 과정에서 비용이 더 소모될 것이고, 아마 플레이리스트와 직접적인 관련이 없는 동작에서도 느려지는 이유가 이것으로부터 나오는 것이 아닐까 싶다. 아님 말고^^;;

비교를 위해 속도가 빠른 Naver 뮤직에서 확인해보니 각 엘리먼트에 직접 이벤트를 할당한 것은 60개를 넘기지 않았고, 리스트 각 항목의 버튼에 걸린 이벤트는 모두 이벤트 위임 방식으로 처리되어 있었다. 물론 Naver 뮤직은 반응형, 동적 웹도 아니었다.

앞서 말한 것처럼 FLO 뮤직의 장점은 추천 플레이리스트를 구독, 등록해서 음악을 듣는 것인데, 이러다보면 결국 플레이 리스트에 등록된 곡 수가 많아질 수밖에 없고, 그럼 웹사이트 동작이 느려지게 된다. 빨리 최적화를 해줬으면 좋겠다.