5. 비동기 큐 지연
5.1 개요
비동기 큐는 콜백 함수의 관리 및 호출을 향상시키는 체인 개체이며 비동기 작업을 처리하는 데 사용됩니다.
비동기 대기열에는 초기화(해결되지 않음), 성공(해결됨), 실패(거부됨)의 세 가지 상태가 있습니다.
어떤 콜백 함수가 실행되는지는 상태에 따라 다릅니다.
상태가 해결 또는 거부로 변경된 후에도 변경되지 않습니다.
콜백 함수 바인딩은 동기식 또는 비동기식일 수 있습니다. 즉, 언제든지 바인딩할 수 있습니다.
(이 섹션에 바인딩 등록을 추가한 것도 같은 의미입니다.)
5.2 주요 메서드
우선 jQuery의 주요 메서드를 살펴보겠습니다.
분류
메서드
설명
deferred.done() 추가
성공 콜백 함수 추가
상태 성공(해결) 시 즉시 호출
deferred.fail()
실패 콜백 함수 추가
status
거부(거부)되면 즉시 deferred.then() 호출
성공 콜백 함수와 실패 콜백 함수를 해당 큐에 추가
편의 방법, 두 매개변수는 배열 또는 null일 수 있음
status 상태 성공(해결) 시 성공 콜백 함수 즉시 호출
상태 실패(거부) 시 실패 콜백 함수 즉시 호출
deferred.always()
콜백 함수 추가 및 추가 성공큐와 실패큐에 동시에 넣습니다
상태가 결정되면 즉시 콜백 함수를 호출합니다(성공, 실패 여부에 관계 없음)
Execute
deferred.resolve()
성공 호출 콜백 함수 대기열
deferred.resolveWith()를 호출하여 달성
deferred.resolveWith()
지정된 컨텍스트와 매개변수를 사용하여 성공 콜백 함수 실행
deferred.reject()
실패 호출 콜백 함수 대기열
deferred.rejectWith()를 호출하여
deferred를 구현합니다. RejectWith()
지정된 컨텍스트와 매개변수를 사용하여 실패 콜백 함수 대기열을 실행합니다
Others
deferred.isRejected()
상태가 성공(해결됨)인지 확인
deferred.isResolved()
상태가 실패(거부됨)인지 확인
deferred.pipe()
들어오는 성공 필터 함수 또는 실패 호출 콜백 함수를 호출할 때마다 필터 함수를 호출하고 필터 함수의 반환 값을 콜백 함수로 사용합니다.
매개변수는 최종적으로 읽기 전용 뷰를 반환합니다(promise를 호출하여 구현됨)
deferred.promise()
deferred의 읽기 전용 보기를 반환합니다.
다음으로 jQuery._Deferred 및 jQuery.Deferred의 소스 코드를 자세히 분석합니다.
5.3 jQuery._Deferred
지역 변수
// 참조:
// 공식 웹사이트 문서 http://api.jquery.com/category/deferred-object/
// 지연 메커니즘 http:// www.cnblogs.com/fjzhou/archive/2011/05/30/jquery-source-3.html
// jQuery 1.5에서 지연된 개체 사용 http://developer.51cto.com/art/201103/248638 . htm
// 돋보기로 Promises 보기 http://www.cnblogs.com/sanshi/archive/2011/03/11/1981789.html
// Promises/A http://wiki. commonjs .org/wiki/Promises/A
var // Promise 메서드
// 다음 메서드가 없다는 점에 유의하세요. 취소 등.
promiseMethods = "done failure isResolved isRejected promise then Always Pipe".split( " " ),
// 슬라이스에 대한 정적 참조
// 슬라이스 메서드에 대한 정적 참조, 누워서 닭을 빌려옴 egg
sliceDeferred = [].slice;
_Deferred:
_Deferred: function() {
var // 콜백 목록
// 콜백 함수 배열(여기서는 개념을 피하기 위해 대기열로 번역되지 않음) 혼란)
callbacks = [],
// 저장된 [ context, args ]
// 컨텍스트와 매개변수를 저장하고 실행이 완료되었는지 여부도 식별할 수 있습니다(fired는 비어 있지 않음을 의미함) 완료됨)
// 여기서 "완료"는 콜백 함수 배열의 "기존" 함수가 모두 실행되었음을 의미합니다.
// 하지만 콜백 함수를 추가하기 위해 done을 다시 호출할 수 있습니다. 추가, 실행은 0으로 재설정됩니다.
실행됨,
// 이미 실행 중인 경우 실행을 방지하기 위해
// 트리거가 이미 실행 중인 경우 다시 실행하지 마세요
실행,
/ / 지연된 작업이 취소되었는지 여부를 알 수 있는 플래그
// 비동기 대기열이 취소되었는지 식별합니다. 취소, 완료됨 해결에 대한 호출은 취소 후 무시됩니다.
cancelled,
// 비동기 대기열 정의( 이것이 실제 소유자입니다. 위의 지역 변수는 클로저를 통해 참조됩니다.)
// 연기된 자체
deferred = {
// done( f1, f2, ...)
// 추가 상태가 성공(해결)되면 즉시 호출되는 성공 콜백 함수
done: function() {
// 취소되면 이 호출을 무시합니다
if ( !cancelled ) {
// 후속 코드에서 사용되는 지역 변수를 코드 블록 시작 부분에 정의하면 장점:
// 1. 변수 선언, 코드 가독성 향상
// 2. 공유 변수, 성능 향상
/ / 참고: 다년간의 Java 작성 경험으로 인해 전역 변수는 처음에 정의하고 임시 변수는 사용할 때마다 정의하는 습관이 생겼습니다.
var args = 인수, / / 콜백 함수 배열
i, // 트래버스 변수
length, // 콜백 함수 배열 길이
elem, // 단일 콜백 함수
type, // elem 유형
_fired; Fire의 임시 백업에 사용됩니다(Fired에 컨텍스트와 매개변수가 저장됨)
// 실행이 완료된 경우(즉, Fire에 컨텍스트와 매개변수가 유지됨)
// 컨텍스트와 매개변수를 백업합니다. _fired로 설정하고 0으로 설정
if (fired) {
_fired = Fired;
fired = 0;
}
// 콜백 함수 배열에 인수 함수 추가
( i = 0, length = args.length; i < length; i ) {
elem = args[ i ]
type = jQuery.type( elem )// array, recursively call
if ( type === "array" ) {
// 강제로 컨텍스트를 deferred로 지정합니다. 개인적으로 컨텍스트는 기본적으로 다음과 같기 때문에 여기서는 컨텍스트를 지정할 필요가 없다고 생각합니다. deferred
deferred.done.apply( deferred, elem );
} else if ( type === "function" ) {
callbacks.push( elem )
}
}
// 실행되었다면(_fired는 Deferred의 상태가 결정되었음을 나타냄) 새로 추가된 함수를 즉시 실행합니다
// 이전에 지정된 컨텍스트 컨텍스트 및 매개변수 인수를 사용합니다
if ( _fired ) {
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
}
}
return this;
},
// 주어진 컨텍스트와 인수로 해결
// 실행, 지정된 컨텍스트 및 매개변수 사용
resolveWith: function( context, args ) {
// 다음 조건이 모두 충족되는 경우에만 실행됩니다: 취소 없음, 실행 없음, 실행 완료 없음
// 취소 또는 완료되었거나 실행 중인 경우 이 호출은 무시됩니다.
if ( !cancelled && !fired && !firing ) {
// 인수가 사용 가능한지 확인하세요(#8421)
// null 및 정의되지 않은 ReferenceError를 방지하기 위한 일반적인 기술인 args가 사용 가능한지 확인합니다.
args = args ||
// 실행 중 실행을 1로 변경합니다.
fireing = 1 ;
try {
// 동적 배열 탐색을 위한 팁
while( callbacks[ 0 ] ) {
// 여기서는 지정된 컨텍스트가 사용되지만
callbacks.shift( ).apply( context, args );
}
}
// JavaScript는 try/catch/finally를 지원합니다.
finally {
fired = [ context, args ]
fired = 0;
}
}
return this;
},
// 이것을 컨텍스트 및 주어진 인수로 해결합니다.
// 상태를 해결됨으로 설정합니다
// 실행 및 실행 상태를 확인하기 위해 isResolved를 호출하여 Resolved 여부를 가져오기 때문에 설정에 대한 이해가 정확하지 않습니다.
//
resolve: function() {
deferred.resolveWith( this, 인수 )
return this;
},
// 이 지연됨 해결되었나요?
// 실행(또는 해결)되었나요?
// 실행 중 또는 실행 후에는 실행/해결된 것으로 간주됩니다
// "Already"는 실행 중에도 실행된 것으로 간주되므로 부정확할 수 있습니다.
isResolved: function( ) {
// 실행 중
// 또는
// 완료됨(즉, 실행이 비어 있지 않음/0)
return !!( 실행 || 실행됨
},
// 취소
// 비동기 대기열 취소
// 플래그 비트를 설정하고 함수 대기열 지우기
cancel: function() {
cancelled =
callbacks = [];
반환
}
};
반환 연기
}
5.4 jQuery.Deferred
코드 복사 코드는 다음과 같습니다.
// 완전한 연기(두 개의 콜백 목록)
// 완전한 비동기 대기열 생성(두 개의 콜백 함수 배열 포함)
// 비동기 대기열에는 세 가지 상태가 있습니다: 초기화(해결되지 않음) , 성공(해결됨), 실패(거부됨).
// 어떤 콜백 함수가 실행되는지는 상태에 따라 다릅니다.
// 상태가 해결됨 또는 거부됨으로 변경된 후에도 변경되지 않습니다.
Deferred: function( func ) {
// _Deferred에는 성공 또는 실패 상태가 없습니다. 초기화, 실행, 실행 완료, 취소의 네 가지 상태가 있습니다.
// 코드 재사용을 위해 내부에서 먼저 _Deferred를 구현했습니다.
// 클로저를 통해 참조되는 failureDeferred
var deferred = jQuery._Deferred(),
failDeferred = jQuery._Deferred(),
promise
// errorDeferred 메서드 추가, then 및 promise
jQuery.extend( deferred, {
// 성공 콜백 함수와 실패 콜백 함수를 해당 큐에 추가
// 편의 메서드, 두 매개 변수는 배열 또는 null일 수 있음
// 즉시 호출 상태가 성공(해결)인 경우 성공 콜백 함수
// 상태가 실패(거부)인 경우 즉시 실패 콜백 함수를 호출합니다.
then: function( doneCallbacks, failureCallbacks ) {
/ / 가 있습니다. 여기에서 컨텍스트 전환: done이 deferred를 반환하지만, 실패는 실패가 실행될 때, 컨텍스트가 failureDeferred로 변경됩니다.
// 간단히 말하면:
// 호출할 때 deferred에 콜백을 추가합니다. done 함수 doneCallbacks
// 실패 실패 콜백을 호출할 때 failureDeferred에 콜백 함수를 추가합니다.
// 따라서 이 표현식 줄이 실행된 후, failureDeferred
deferred.done( doneCallbacks ).fail( 실패Callbacks ); 🎜>// 강제 반환 연기
return this;
},
// 해결 또는 거부 여부에 따라 호출되는 콜백 함수를 등록합니다.<… {
// done의 컨텍스트는 deferred로 설정되고, 실패의 컨텍스트는 이것으로 설정됩니다.
// done과 failure의 컨텍스트가 일치하지 않나요? 일관된! 여기서는 deferred와 같습니다
// 그런데 이렇게 설정된 컨텍스트를 어떻게 해석해야 할까요? 그때의 구현과 어떻게 다른가요?
// 실패는 실패 지점이고 실패는 실패 Deferred입니다. 실패Deferred의 콜백 함수 배열 콜백은 클로저를 통해 참조됩니다. deferred.failDeferred.done의 실행에는 영향을 미치지 않습니다.
// 체인 호출을 구현하려면 실패Deferred.done의 끝에서 이것을 deferred로 바꿉니다.
// 즉, 이 컨텍스트는 도중에 손실되지 않습니다. 이러한 혼란을 일으키지 않고 다른 체인 호출을 계속 호출할 수 있습니다
// 문법적으로 Always 에 의해 달성되는 효과는 then에 의해 달성되는 효과와 일치합니다
// 따라서 이는 한 줄의 코드를 두 줄로 다시 작성할 수 있으며( then 구현과 유사) 효과는 동일합니다.
// deferred.done( 인수 ).fail( 인수 )
// returnr this; >return deferred.done.apply( deferred, 인수 ).fail.apply( this, 인수 );
},
// 실패 콜백 함수 추가
// 실패 상태일 때 즉시 호출됨(거부됨) )
fail: 실패Deferred.done,
// 지정된 컨텍스트와 매개변수를 사용하여 실패 콜백 함수 대기열을 실행합니다
// 실패Deferred.rejectWith()를 호출하여
rejectWith: 실패Deferred.resolveWith,
// 실패 콜백 함수 대기열이 호출됩니다
// failureDeferred .resolve()를 호출하여
reject: 실패Deferred.resolve,
// 상태가 성공(해결됨)인지 확인
isRejected : failureDeferred.isResolved,
// 매번 전달된 콜백 함수를 호출합니다. 성공 필터 함수 또는 실패 필터 함수를 입력하고, 필터 함수의 반환 값을 콜백 함수의 매개 변수로 사용합니다.
// 최종 반환 읽기 전용 뷰(구현 약속 호출)
// fnDone이 성공 상태인지 여부(해결되면 호출됨)
// 상태가 거부될 때 fnFail이 호출됨(rejected)
/ / 기타 설명에 대해:
// 1. 일부 기사는 "파이프라인 메커니즘"으로 번역됩니다. 문자 그대로의 의미를 이해할 수 없으므로 적어도 부정확합니다
// 2. 잘못된 이해: 소위 파이프는 들어오는 fnDone 및 fnFail을 성공 대기열 및 실패 대기열 배열의 헤드에 넣습니다
pipe : function( fnDone, fnFail ) {
return jQuery.Deferred(function( newDefer ) {
jQuery.each( {
done: [ fnDone, "resolve" ], // done은 나중에 텍스트 deferred.done
fail: [ fnFail, "reject" ]
}, function ( 핸들러, 데이터 ) {
var fn = data[ 0 ],
action = data[ 1 ],
returned
if ( jQuery.isFunction( fn ) ) {
deferred[ handler ](function() {
returned = fn.apply( this, 인수 );
if ( return && jQuery .isFunction( return.promise ) ) {
returned.promise().then( newDefer .resolve, newDefer.reject );
} else {
newDefer[ 액션 ]( 반환됨 )
}
}) else {
deferred[ 핸들러 ]( newDefer [ action ] );
}
});
}).promise();
} ,
// obj가 제공되는 경우 , Promise 측면이 개체에 추가됩니다
// 반환되는 것은 해결 및 거부가 없는 불완전한 Deferred 인터페이스입니다. 즉, Deferred 개체의 상태를 수정할 수 없습니다.
// 이는 방지하기 위한 것입니다. 외부 함수는 콜백 함수를 조기에 트리거하지 않으며 읽기 전용 뷰로 간주될 수 있습니다.
//
// 예를 들어 $.ajax는 버전 1.5 이후 더 이상 XMLHttpRequest를 반환하지 않지만 XMLHttpRequest 및 Deferred 개체 인터페이스를 캡슐화하는 개체를 반환합니다.
// Deferred 부분은 promise()에 의해 획득됩니다. 이는 외부 함수가 Resolve 및 Reject를 호출하는 것을 방지하고 Ajax가 완료되기 전에 콜백 함수가 트리거되는 것을 방지합니다.
// 이 두 함수의 호출 권한을 Ajax 내부적으로 예약하세요.
promise: function( obj ) {
if ( obj == null ) {
// Promise는 실제로 한 번만 실행되며 첫 번째 실행 결과는 Promise 변수에 저장됩니다
if ( promise ) {
return promise;
}
promise = obj = {};
}
var i = promiseMethods.length;// <를 반복하는 또 다른 방법 🎜 >// 나는 다음을 사용하는 데 익숙합니다:
// for( i = 0; i < len; i ) 또는 for( i = len-1; i >=0; i-- ) 또는 for( i = len ; i--; )
// jQuery는 정말 어디에서나 보물입니다!
while( i-- ) {
obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]
}
return obj;
}
}); 🎜>// 하나의 콜백 목록만 사용하도록 하세요
// 성공적인 큐 실행이 완료된 후 실패 큐 취소 메소드가 실행됩니다
// 실패 큐 실행이 완료된 후 성공한 큐가 취소 메서드가 실행됩니다
// 하나의 함수 큐, 즉 실행 성공 큐 또는 실행 실패 큐만 실행되도록 합니다.
// 즉, 상태는 성공 또는 하나만 가능합니다. 실패, 교차 호출 없음
// deferred 및 실패Deferred의 취소된 속성은 클로저를 통해서만 참조할 수 있으므로 상태와 컨텍스트의 혼동에 대해 걱정할 필요가 없습니다
deferred.done( failureDeferred.cancel ).fail( deferred.cancel );
// Unexpose cancel
// 취소 인터페이스를 숨깁니다. 즉, 성공한 함수 대기열을 외부에서 취소할 수 없습니다.
deferred.cancel
// 호출 func if any
// 수신 func 함수 실행
if ( func ) {
func.call( deferred, deferred )
return deferred;
5.5 jQuery.when
코드 복사
var args = 인수,
i = 0,
length = args.length,
count = length,
//args.length가 1이고 firstParam이 Deferred인 경우 deferred=firstParam
// 그렇지 않은 경우 , 새 Deferred 객체 생성(arguments.length가 0이거나 1보다 큰 경우 새 Deferred 객체 생성)
// jQuery.isFunction( firstParam.promise )을 통해 Deferred 객체인지 여부를 간단히 확인
deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
firstParam :
jQuery.Deferred()
// 성공적인(해결) 콜백 함수 구성
functionsolveFunc( i ) {
return function( value ) {
// 전달된 매개변수가 1보다 크면 들어오는 매개변수를 실제 배열로 변환합니다(인수에는 슬라이스 메서드가 없으므로 빌림). 알을 낳을 닭)
args[ i ] = 인수.길이 > 1 ? SliceDeferred.call( 인수, 0 ) : value; / FF4의 이상한 버그:
// 인수 객체로 변경된 값이 $.when 메소드 외부에서 정의되지 않은 값으로 끝나는 경우가 있습니다. 객체를 새로운 배열로 복제하면 문제가 해결됩니다. 🎜>// 성공적으로 실행된 콜백 함수 큐, 컨텍스트는
deferred.resolveWith( deferred, SliceDeferred.call( args, 0 ) )
}
}에 전달된 첫 번째 Deferred 객체로 강제 적용됩니다. 🎜>}
// 매개변수가 두 개 이상인 경우
if ( length > 1 ) {
for( ; i < length; i ) {
// 간단히 여부만 확인 지연된 객체인 경우 .promise().then()을 호출하고, 그렇지 않으면
if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
//성공 콜백 추가를 무시합니다. 함수 및 실패 콜백 함수를 해당 대기열에
args[ i ].promise().then( resolveFunc(i), deferred.reject )
} else {
// 카운터, 이를 나타냅니다. Deferred 객체가 아니라 일반 JavaScript 객체임을 발견했습니다.
--count;
}
}
// 카운터가 0이면 전달된 매개변수가 하나도 없다는 뜻입니다. 지연된 객체
// 실행 성공 콜백 함수 대기열, 컨텍스트는 강제로 전달된 첫 번째 지연된 객체가 됩니다.
if ( !count ) {
deferred.resolveWith( deferred, args )
}
// deferred !== firstParam, 즉 deferred는 새로 생성된 Deferred 객체입니다.
// 즉, length == 0
} else if ( deferred !== firstParam ) {
// 성공적인 실행을 위한 콜백 함수 대기열, 컨텍스트는 새로 생성된 Deferred 객체에 강제 적용됩니다.
deferred.resolveWith( deferred, length ? [ firstParam ] : [] )
// 첫 번째 반환 전달된 지연 또는 새로 생성된 객체의 지연된 읽기 전용 보기
return deferred.promise();
}
5.6 지연된 애플리케이션
l jQuery. ajax()
n TODO
5.7 배울 수 있는 기술
l 클로저
코드 복사
코드
function a(){
var guid = 1
return function(){
return guid ; >var defer = a();
console.info( defer() ); // 1 console.info( defer() ) // 2 console.info( defer() ); // 3 console.info( defer() ) // 4 l null 및 정의되지 않은 ReferenceError를 방지하기 위한 일반적인 기술
args = args []
l 동적 배열을 순회하는 기술
while( callbacks[ 0 ] ) {
콜백. Shift ().apply( context, args );
}
l 오류 처리 구현을 위한 try/catch/finally
구문
설명
try {
// tryStatements
} catch ( 예외 ) {
// catchStatements
} finally {
// finallyStatements
}
tryStatements
필수입니다.
잘못된 진술이 있을 수 있습니다.
예외
필수입니다. 임의의 변수 이름.
Exception의 초기화 값은 발생한 오류의 값입니다.
catchStatements
선택사항.
연관된 tryStatement에서 발생하는 오류를 처리하는 문입니다.
finallyStatements
선택 사항.
다른 모든 프로세스가 발생한 후에 무조건 실행되는 명령문입니다.
l 연결된 객체: this를 반환하여 연결된 호출 구현
메서드
반환 값
done
this(즉, 지연됨)
resolveWith
this(즉, 지연됨)
resolve
이것(즉, 연기됨)
취소
이것(즉, 연기됨)
l 코드 재사용 $.each
jQuery.each( {
done: [ fnDone, "resolve " ], // done은 기사 뒷부분의 deferred.done을 가리킵니다.
fail: [ fnFail, "reject" ]
}, function( handler, data ) {
// 공개 코드 재사용
}) ;
5.8 후속 조치
l jQuery에서 Deferred 적용
l Deferred의 사용자 정의 적용