실패 한 jQuery 최적화 시도 소결

(이것 은 jQuery 의 성능 이 우수 하 다 는 것 을 의미 하 는 것 이 아니 라 상대 적 으로 폐쇄 된 라 이브 러 리 라 고 할 수 있 을 뿐 외부 개입 으로 최적화 할 수 없다).이 글 은 실패 의 최적화 경험 을 한 번 기록 하고 있다.사상 을 최적화 하 는 이번 최적화 사상 은 데이터베이스 에서 나온다.데이터 베 이 스 를 최적화 할 때 우 리 는 항상"대량의 조작 을 한 업무 에 함께 제출 하면 효율 을 효과적으로 높 일 수 있다"고 말한다.데이터 베 이 스 를 모 르 는 나 는 그 이 유 를 모 르 지만'사무'의 사상 은 나 에 게 방향 을 가 리 켜 주 었 다.그래서 저 는'사무'라 는 개념 을 jQuery 에 도입 하려 고 합 니 다.'열기'와'제출'사 무 를 통 해 외부 에서 jQuery 를 최적화 시 키 려 고 합 니 다.가장 중요 한 것 은 each 함수 의 순환 횟수 를 줄 이 는 것 입 니 다.알다 시 피 jQuery 의 DOM 작업 은 get all,set first 를 기준 으로 하 는데 그 중에서 DOM 속성/스타일 을 설정 하 는 작업 에 사용 되 고 선택 한 요 소 를 한 번 에 옮 겨 다 니 는 것 입 니 다.jQuery.access 함 수 는 그 중에서 가장 핵심 적 인 부분 입 니 다.그 중에서 순환 에 사용 되 는 코드 는 다음 과 같 습 니 다.
 
// Setting one attribute
if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = !pass && exec && jQuery.isFunction(value);
for ( var i = 0; i < length; i++ ) {
fn(
elems[i],
key,
exec ? value.call(elems[i], i, fn(elems[i], key)) : value,
pass
);
}
return elems;
}
예 를 들 어 jQuery.fn.css 함수 가 바로 다음 과 같 습 니 다.
 
jQuery.fn.css = function( name, value ) {
// Setting 'undefined' is a no-op
if ( arguments.length === 2 && value === undefined ) {
return this;
}
return jQuery.access( this, name, value, true, function( elem, name, value ) {
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
});
};
따라서다음 코드 는 선택 한 div 요소 가 5000 개 라 고 가정 하면 10000 개의 노드 를 반복 적 으로 방문 해 야 합 니 다.jQuery('div').css('height',300).css('width',200).한편,제 생각 에는'사무'에서 데이터 베 이 스 를 조작 하 는 것 처럼 모든 조작 을 저장 하고'사무 제출'할 때 통일 적 으로 진행 하여 10000 번 의 노드 방문 을 5000 번 으로 줄 이 는 것 은'1 배'의 성능 을 향상 시 키 는 것 과 같 습 니 다."사무"식 jQuery 작업 을 간단하게 수행 할 때 2 개의 함 수 를 제공 합 니 다.begin:"사무"를 열 고 업무 의 대상 을 되 돌려 줍 니 다.이 대상 은 jQuery 의 모든 함 수 를 가지 고 있 지만 호출 함 수 는 즉각 효력 이 발생 하지 않 으 며,'제출 사무'후에 만 효력 이 발생 합 니 다.commt:"사무"를 제출 하여 미리 호출 된 모든 함수 가 유효 하도록 합 니 다.원래 jQuery 대상 에 게 돌려 줍 니 다.실현 하기 도 편리 합 니 다."사무 대상"을 만 들 고 jQuery.fn 의 모든 함 수 를 이 대상 에 복사 합 니 다.어떤 함 수 를 호출 할 때 미리 준 비 된'대기 열'에 호출 된 함수 이름과 관련 인 자 를 추가 합 니 다.사 무 를 제출 할 때 선택 한 요 소 를 한 번 옮 겨 다 니 며 옮 겨 다 니 는 모든 노드 에'대기 열'의 모든 함 수 를 적용 합 니 다.간단 한 코드 는 다음 과 같다.
 
var slice = Array.prototype.slice;
jQuery.fn.begin = function() {
var proxy = {
_core: c,
_queue: []
},
key,
func;
// jQuery.fn
for (key in jQuery.fn) {
func = jQuery.fn[key];
if (typeof func == 'function') {
// for key
// key (LIFT )
(function(key) {
proxy[key] = function() {
//
this._queue.push([key, slice.call(arguments, 0)]);
return this;
};
})(key);
}
}
// commit
proxy.commit = jQuery.fn.commit;
return proxy;
};
jQuery.fn.commit = function() {
var core = this._core,
queue = this._queue;
// each
core.each(function() {
var i = 0,
item,
jq = jQuery(this);
//
for (; item = queue[i]; i++) {
jq[item[0]].apply(jq, item[1]);
}
});
return this.c;
};
테스트 환경 테스트 는 다음 과 같은 조건 을 사용한다.5000 개의 div 를 한 용기(
)에 넣는다.$('\#container>div')를 사용 하여 이 div 5000 개 를 선택 하 십시오.div 마다 무 작위 배경 색(randomColor 함수)과 800 px 이하 의 무 작위 너비(randomWidth 함수)를 설정 해 야 합 니 다.테스트 에 참가 하 는 호출 방법 은 3 가지 가 있 습 니 다.정상 적 인 사용법:
 
$('#container>div')
.css('background-color', randomColor)
.css('width', randomWidth);
1 차 순환 법:
 
$('#container>div').each(function() {
$(this).css('background-color', randomColor).css('width', randomWidth);
});
사무 법:
 
$('#container>div')
.begin()
.css('background-color', randomColor)
.css('width', randomWidth)
.commit();
대상 할당 법:
 
$('#container>div').css({
'background-color': randomColor,
'width': randomWidth
});
테스트 브 라 우 저 는 Chrome 8 시 리 즈 를 선택 합 니 다(IE 테스트 로 바로 끊 습 니 다).슬 픈 결 과 는 원래 예측 한 결과 1 차 순환 법의 효율 이 정상 적 인 사용 법 보다 훨씬 높 고,동시에 사무 법 은 1 차 순환 법 보다 느 리 지만 정상 적 인 사용 법 보다 빨 라 야 하 며,대상 할당 법 은 jQuery 내부 에서 지원 하 는 1 차 순환 법 으로 효율 이 가장 높 아야 한다.그러나 안 타 깝 게 도 결 과 는 다음 과 같다.정상 적 인 사용 법 1 차 순환 법 사무 법 대상 할당 법 18435 ms 18233 ms 18918 ms 17748 ms 는 결과 적 으로 볼 때 사무 법 이 가장 느 린 방법 이 되 었 다.또한 1 차 순환 과 정상 적 인 사용 은 현저 한 장점 이 없고 심지어 jQuery 내부 에서 이 루어 진 대상 할당 법 에 의존 하 는 것 도 큰 차이 가 없다.5000 개의 요소 의 조작 은 이미 매우 방대 한 순환 이기 때문에 이렇게 방대 한 순환 도 성능 의 차 이 를 벌 리 지 못 했다.평소에 가장 자주 사용 하 는 10 개 정도 의 요소 조작 은 현저 한 장점 을 가지 지 못 하고 심지어 약점 을 확대 할 수도 있다.그 원인 을 따 져 보면 그 자체 의 1 차 순환 법 은 뚜렷 한 성능 향상 이 없 기 때문에 1 차 순환 에 의존 하고 1 차 순환 위 에서 외부 구축 을 하 는 사무 법 이다.자 연 스 럽 게 1 차 순환 을 바탕 으로 사무 대상 을 만 들 고 함수 대기 열 을 저장 하 며 함수 대기 열 을 옮 겨 다 니 는 등 비용 을 추가 로 늘 려 야 하 며 결 과 는 정상 적 인 사용 법 에 패 하 는 것 도 도리 에 있다.이로써'사무'를 모방 한 최적화 의 길 을 선포 할 수 있 는 실패 라 고 할 수 있다.하지만 이 결과 에 대해 서 는 좀 더 분석 할 수 있다.성능 이 어디 에 있 는 지 먼저 코드 의 사용 을 분석 하고 정상 적 인 사용법 과 테스트 에서 가장 빠 른 대상 할당 법 을 비교 한 결과 이들 의 차 이 는 순환 하 는 요소 개수 의 차이 에 있다 고 할 수 있다.정상 적 인 사용 법 은 10000 개의 요소 이 고 대상 할당 법 은 5000 개의 요소 이다.따라서 18435-17748=687 ms 는 5000 개의 요 소 를 순환 하 는 데 걸 리 는 시간 으로 전체 집행 과정의 3.5%정 도 를 차지 하고 전체 집행 과정의 주간 이 아니 라 사실은 최적화 할 필요 가 없다 고 간단하게 볼 수 있다.그럼 나머지 96.5%는 어디로 갔 을 까?"사실 자 바스 크 립 트 는 느 리 지 않 고 느 린 것 은 DOM 의 조작"이라는 도 글 러 스 의 한 마디 를 명심 하 라.사실 남 은 96.5%의 비용 중에서 함수 호출 등 기본 적 인 소 모 를 제외 하고 적어도 95%의 시간 은 DOM 요소 의 스타일 이 바 뀐 후에 다시 렌 더 링 하 는 데 사용 된다.이 사실 을 발견 한 후에 사실은 더욱 정확 한 최적화 방향 이 생 겼 고 전단 성능 의 기본 원칙 중 하나 이다.대량의 서브 요 소 를 수정 할 때 먼저 뿌리 부모 DOM 노드 를 DOM 트 리 로 옮 겼 다.따라서 다음 과 같은 코드 를 사용 하여 테스트 를 한다 면
 
// $('#container')
$('#container').detach().find('div')
.css('background-color', randomColor)
.css('width', randomWidth);
$('#container').appendTo(document.body);
테스트 결 과 는 900 ms 정도 에 머 물 렀 고 앞의 데이터 와 수량 급 이상 이 아니 라 진정한 최적화 에 성공 했다.교훈 과 정 리 는 정확 한 성능 병목 을 찾 아 최적화 시 켜 야 한다.맹목적 인 추측 은 잘못 되 고 과격 한 길 을 걷 게 될 뿐이다.데이터 앞에서 아무 도 말 하지 마!'사무'라 는 방향 이 틀 렸 다 고 생각 하지 않 는 다.jQuery 원생 이'사무'라 는 개념 을 지원 할 수 있다 면 다른 점 이 최적화 되 지 않 을 까?예 를 들 어 하나의 사무 가 자동 으로 부모 요 소 를 DOM 트 리 에서 벗 어 나 게 하 는 것 과 같은...

좋은 웹페이지 즐겨찾기