jQuery는 편리하지만, 잘못 사용하면 웹사이트 성능을 크게 떨어뜨릴 수 있다. 특히 대규모 프로젝트에서 jQuery를 남용하거나 최적화하지 않으면 페이지 로딩 속도, 메모리 사용량 등 여러 문제가 발생한다. 이번에는 jQuery를 사용할 때 자주 하는 실수들과 그 해결책을 정리해서 소개하겠다. 

 

이 글을 읽고 당신의 jQuery 코드를 점검해보면, 분명히 개선할 부분들을 발견할 수 있을 것이다. 

 

실수 1: 같은 요소를 반복해서 선택하기

✗ 잘못된 코드

// 같은 요소를 여러 번 선택 - 매번 DOM을 탐색해서 느림
$('#myDiv').html('Hello');
$('#myDiv').css('color', 'red');
$('#myDiv').addClass('active');

// 상황에 따라 루프 안에서 선택하면 더욱 느림
for(var i = 0; i < 1000; i++) {
   $('li').eq(i).text('Item ' + i);  // 1000번 선택
}

✓ 올바른 코드

// 한 번만 선택해서 변수에 저장
var $myDiv = $('#myDiv');
$myDiv.html('Hello');
$myDiv.css('color', 'red');
$myDiv.addClass('active');

// 루프는 다르게 처리
var $items = $('li');
$items.each(function(i) {
   $(this).text('Item ' + i);
});

// 또는 더 효율적으로
var html = '';
for(var i = 0; i < 1000; i++) {
   html += '<li>Item ' + i + '</li>';
}
$('#list').html(html);  // 한 번만 DOM 조작

 

실수 2: 복잡한 선택자 사용

✗ 잘못된 코드

// 복잡한 선택자 - 느림
$('div.container div.row div.col-md-6 p.text-bold')

// CSS 수도 선택자도 성능이 안 좋음
$('p:contains("hello")').css('color', 'red');

// 여러 선택자 조합
$('.class1.class2.class3.class4')

✓ 올바른 코드

// 단순한 선택자 사용
$('p.text-bold')

// 변수에 저장
var $container = $('#container');
$container.find('p').css('color', 'red');

// 처음부터 구조를 단순하게 설계

 

실수 3: 동적으로 생성된 요소에 이벤트 리스너 직접 바인딩

✗ 잘못된 코드

// 페이지 로드 시점의 요소에만 이벤트 바인딩됨
$('.delete-btn').click(function(){
   $(this).parent().remove();
});

// 나중에 AJAX로 추가된 버튼에는 이벤트가 작동 안 함

✓ 올바른 코드

// 이벤트 위임(Event Delegation) 사용
$(document).on('click', '.delete-btn', function(){
   $(this).parent().remove();
});

// 또는 상위 컨테이너에서 위임
$('#container').on('click', '.delete-btn', function(){
   $(this).parent().remove();
});

// 좀 더 효율적 - 정적인 상위 요소에 바인딩
$('#staticParent').on('click', '.delete-btn', function(){
   $(this).parent().remove();
});

 

실수 4: 과도한 DOM 조작

✗ 잘못된 코드

// 반복할 때마다 DOM을 조작 - 매우 느림
var data = ['item1', 'item2', 'item3', 'item4', 'item5'];
for(var i = 0; i < data.length; i++) {
   $('#list').append('<li>' + data[i] + '</li>');  // 5번 DOM 조작
}

✓ 올바른 코드

// 문자열을 먼저 조합한 후 한 번에 DOM에 추가
var data = ['item1', 'item2', 'item3', 'item4', 'item5'];
var html = '';
for(var i = 0; i < data.length; i++) {
   html += '<li>' + data[i] + '</li>';
}
$('#list').append(html);  // 1번만 DOM 조작

// 또는 배열 join 활용
var html = data.map(function(item) {
   return '<li>' + item + '</li>';
}).join('');
$('#list').append(html);

 

실수 5: 메모리 누수 - 이벤트 리스너 미제거

✗ 잘못된 코드

// 모달을 열 때마다 새로운 이벤트 리스너가 추가됨 - 메모리 누수
$('#openModal').click(function(){
   $('#modal').show();
   $('#modal .close').click(function(){
      $('#modal').hide();
   });
});

✓ 올바른 코드

// 한 번만 바인딩
$(document).ready(function(){
   $('#openModal').click(function(){
      $('#modal').show();
   });
   
   $('#modal .close').click(function(){
      $('#modal').hide();
   });
});

// 또는 요소 제거 시 이벤트도 제거
var closeModal = function(){
   $('#modal').hide();
   $('#modal .close').off('click', closeModal);  // 이벤트 제거
};

 

실수 6: 불필요한 정규표현식 사용

✗ 잘못된 코드

// :contains는 정규표현식 사용하고 매우 느림
$('p:contains("error")').css('color', 'red');

// 같은 이유로 :has도 느림
$('div:has(.special)')

✓ 올바른 코드

// 직접 요소를 선택하거나 find 사용
$('p').filter(function(){
   return $(this).text().indexOf('error') !== -1;
}).css('color', 'red');

// 또는 처음부터 클래스 사용
$('p.error').css('color', 'red');

// 또는 find 사용
$('div').find('.special').parent()

 

실수 7: 계속 $.ajax() 호출하기 (중복 요청)

✗ 잘못된 코드

// 검색 입력할 때마다 서버에 요청 - 너무 많은 요청 발생
$('#searchInput').keyup(function(){
   $.get('search.php', {q: $(this).val()}, function(data) {
      console.log(data);
   });
});

✓ 올바른 코드

// 타이머로 마지막 입력 후 일정 시간 뒤에만 요청
var searchTimer;
$('#searchInput').keyup(function(){
   clearTimeout(searchTimer);  // 이전 타이머 취소
   var query = $(this).val();
   
   searchTimer = setTimeout(function(){
      $.get('search.php', {q: query}, function(data) {
         console.log(data);
      });
   }, 300);  // 300ms 뒤에 요청
});

// 또는 debounce 함수 사용
function debounce(func, wait) {
   var timeout;
   return function() {
      var context = this, args = arguments;
      clearTimeout(timeout);
      timeout = setTimeout(function() {
         func.apply(context, args);
      }, wait);
   };
}

$('#searchInput').keyup(debounce(function(){
   $.get('search.php', {q: $(this).val()});
}, 300));

 

실수 8: 애니메이션 남용

✗ 잘못된 코드

// 모든 동작에 애니메이션 추가 - 성능 저하, 사용자 경험 악화
$('#box').animate({width: 200}, 1000);
$('#box').animate({height: 200}, 1000);
$('#box').animate({opacity: 0.5}, 1000);
$('#box').animate({marginLeft: 50}, 1000);

✓ 올바른 코드

// 필요한 것만, 적당한 시간으로
$('#box').animate({width: 200, height: 200}, 300);

// CSS3 전환 사용 (더 빠름)
$('#box').addClass('animated');

// CSS
// .animated {
//    transition: all 0.3s ease;
//    width: 200px;
//    height: 200px;
// }

 

실수 9: .html() 대신 .text() 사용할 수 있는데 .html() 사용

✗ 잘못된 코드

// HTML 태그 없이 텍스트만 표시할 때도 .html() 사용 - 비효율
$('#message').html('Hello World');  // .html()는 HTML 파싱 필요

✓ 올바른 코드

// 순수 텍스트면 .text() 사용 (더 빠름)
$('#message').text('Hello World');

// HTML 태그가 필요할 때만 .html() 사용
$('#message').html('<strong>Hello</strong> World');

 

실수 10: jQuery 버전 확인 없이 오래된 문법 사용

✗ 잘못된 코드

// 오래된 jQuery 버전만 지원하는 방법들
$('#myElement').live('click', function(){  // live는 jQuery 1.9.1에서 제거됨
   alert('clicked');
});

// .bind도 권장하지 않음
$('#myElement').bind('click', function(){
   alert('clicked');
});

✓ 올바른 코드

// 최신 jQuery에서는 .on() 사용
$('#myElement').on('click', function(){
   alert('clicked');
});

// 또는 동적 요소에는 이벤트 위임
$(document).on('click', '#myElement', function(){
   alert('clicked');
});

 

성능 측정하기

최적화하기 전에 성능을 측정해야 한다:

// console에서 시간 측정
console.time('myTimer');

for(var i = 0; i < 10000; i++) {
   // 테스트할 코드
   var $item = $('#item');
}

console.timeEnd('myTimer');
// 결과: "myTimer: 123.456ms"

 

jQuery는 편리하지만, 편의만 추구하면 성능이 떨어진다. 이번 글의 10가지 실수를 피하고 최적화 팁을 적용하면, jQuery 코드의 성능을 크게 향상시킬 수 있다. 특히 대규모 프로젝트라면 이런 작은 최적화들이 모여서 전체 성능에 큰 영향을 미친다는 점을 잊지 말자.