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 코드의 성능을 크게 향상시킬 수 있다. 특히 대규모 프로젝트라면 이런 작은 최적화들이 모여서 전체 성능에 큰 영향을 미친다는 점을 잊지 말자.