jQuery.Deferredオブジェクトのソースコード解析
11759 ワード
Deferredって何?
実際にdeferredはPromise/A+標準のjQueryの実装であり,非同期操作を管理するオブジェクトである.
jQuery.Deferred大体ロジックソースコードの概略コードは次の です.
まとめ:はtuples、state、promise、deferred変数を宣言する. tuplesをdeferredに混入する. promiseをdeferredに混入する. deferredの構成関数funcがあれば実行する. は最後にdeferredオブジェクトを返す.
配列を構成するtuplesとして tuplesの具体的な定義 を見てみましょう.
まとめ:この配列は実際にdeferred全体の基本メソッド名、ステータス名、コールバック管理コンテナを定義します.
promiseオブジェクト定義 promiseオブジェクトはdeferredの非常に重要なオブジェクトであり、deferredのサブセットであり、一連のコールバック登録関数を定義し、宣言時に次のメンバーオブジェクトがある: 以下でpipeの実装pipeを詳細に説明すると、フック関数として理解することができ、3つのコールバックとして参照され、状態戻り結果を前処理する.ソースコードは次のとおりです:
まとめ: pipe関数は、入力されたコールバックで元のdeferredを装飾し、新しいdeferredオブジェクトを返します. コールバックの戻り値もpromiseやdeferredのような非同期オブジェクトである場合、新しいdeferredの状態はこの戻り値の状態に依存する. 戻り値が非同期オブジェクトである場合、新しいdeferredの状態遷移関数のパラメータとして直接使用される. 新しいdeferredの状態遷移関数のコンテキストは、古いdeferredの状態遷移関数のコンテキストを継承する. コールバックが入力されていない場合、新しいdeferred解析の結果、古いdeferredの状態遷移関数が参照される. 以下thenメソッドの実装thenメソッドはpromise標準のコアメソッドであり、最も複雑な1つでもあり、まずコード:
次にresolve解析法の実装を具体的に見てみましょう.
resolveの深さについては、いくつかの例を挙げます.
まとめ: then注入コールバックは深層の非同期ネストをサポートするが、done、failはできず、所属する非同期オブジェクトの状態解析が完了した後に実行される. thenは非同期のタイミング関係を決定するだけで、各非同期オブジェクトの最終状態が達成されるかどうかを保証するものではないことを意味的に感じることができる.
ここではjQuery.eachはtuplesをpromiseとdeferredに注入する
ソースとコメントを直接見ればいいです.
最后に:私もちょうどjQueryのソースコードを学ぶことを始めて、この文はただノートと心得と分かち合うことを学ぶだけとして、Deferredについて、まだ多くの理解しない地方があって、各位の大きい人の指导を歓迎します
実際にdeferredはPromise/A+標準のjQueryの実装であり,非同期操作を管理するオブジェクトである.
jQuery.Deferred大体ロジック
jQuery.extend(
Deferred: function( func ) {
// 、 、 、
var tuples = [
[ ... ], // fulfilled
[ ... ], // rejected
[ ... ] // progress
],
// ,
state = "pending",
// promise , , done()、fail()、progress()、then() , deferred
promise = { ... },
// deferred , , , promise
deferred = {};
// deferred promise done,fail,progress
// deferred resolve、reject、notify
jQuery.each( tuples, function( tuple, i ) {
...
} );
// promise deferred
promise.promise( deferred );
// Deferred() ,func deferred,
if ( func ) {
func.call( deferred, deferred )
}
// deferred
return deferred;
}
)
まとめ:
配列を構成するtuplesとして
// tuples , deferred , tuple
// tuple[ 0 ]
// tuple[ 1 ]
// tuple[ 2 ] tuple[ 1 ] , resolve reject
// tuple[ 3 ] then()
// tuple[ 4 ] then() ,
// tuple[ 5 ]
var tuples =
[
[ "notify", "progress", jQuery.Callbacks( "memory" ),
jQuery.Callbacks( "memory" ), 2 ],
[ "resolve", "done", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), 0, "resolved" ],
[ "reject", "fail", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), 1, "rejected" ]
]
まとめ:この配列は実際にdeferred全体の基本メソッド名、ステータス名、コールバック管理コンテナを定義します.
promiseオブジェクト定義
promise = {
//
state: function() {
return state;
},
// onFulFilled onRejected
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
// catch , then onRejected
"catch": function() {
return promise.then( null, fn );
},
pipe: function() { ... },
then: function() { ... },
promise: function() { ... }
}
pipe: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
// deferred ,
// deferred
return jQuery.Deffered( function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
// tuple[ 4 ] fn
var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
//
deferred[ tuple[ 1 ] ]( function() {
// fn returned
var returned = fn && fn.call( this, arguments );
// returned promise deferred, promise
// , deferred returned
// Promise/A+
if ( returned && isFunction( returned.promise ) ) {
// deferred returned
returned.promise()
.progress( newDefer.notify )
.done( newDefer.resolve )
.fail( newDefer.reject )
} else {
// ,returned
// , this deferred
// fn, deferred
newDefer[ tuple[ 0 ] + 'With' ](
this,
fn ? [ returned ] : arguments
);
}
} );
} );
fns = null;
} ).promise();
}
まとめ:
then: function( onFulfilled, onReject, onProgress ) {
//
var maxDepth = 0;
// ,
function resolve( depth, deferred, handler, special ) {
// ,
return function() {
...
}
}
// deferred ,
return jQuery.Deferred( function( newDefer ) {
// , then ,
// ,then tuple[ 3 ]
// done、fail、progress tuple[ 2 ]
tuples[ 0 ][ 3 ].add(
resolve(
0,
newDefer,
isFunction( onProgress ) ?
onProgress :
Indentity
)
);
tuples[ 1 ][ 3 ].add(
resolve(
0,
newDefer,
isFunction( onFulfilled ) ?
onFulfilled :
Indentity
)
);
tuples[ 2 ][ 3 ].add(
resolve(
0,
newDefer,
isFunction( onRejected ) ?
onRejected :
Thrower
)
);
} ).promise()
}
次にresolve解析法の実装を具体的に見てみましょう.
function reslove( depth, deferred, handler, specail ) {
return function() {
// , , resolveWith
// that, mightThrow
var that = this,
args = arguments,
mightThrow = function() {
var returned, then;
// depth < maxDepth, depth deferred ,
if ( depth < maxDepth ) {
return;
}
returned = handler.apply( that, args );
// deferred promise,
// deferred ,
if ( returned === deferred.promise() ) {
throw new TypeError( "Thenable self-resolution" );
}
// returned promise , returned.then then
then = returned &&
( typeof returned === "object" ||
typeof returned === "function" ) &&
returned.then;
// then function, returned promise
if ( isFunction( then ) ) {
// special, onProgress , resolve
// function progress , maxDepth, notify
if ( special ) {
then.call(
returned,
resolve( maxDepth, deferred, Indentity, special ),
resolve( maxDepth, deferred, Thrower, special )
);
} else {
// , function done , special deferred.notifyWith
maxDepth++;
then.call(
returned,
resolve( maxDepth, deferred, Indentity, special ),
resolve( maxDepth, deferred, Thrower, special ),
resolve( maxDepth, deferred, Indentity, deferred.notifyWith )
);
}
} else {
// then function, returned value
// handler Indentity, handler
// 0, deferred deferred
if ( handler !== Indentity ) {
that = undefined;
args = [ returned ];
}
// special , notifyWith ,
// handler , fulfilled, deferred.resolveWith
( special || deferred.resolveWith )( that, args );
}
},
// special notify , , mightThrow
// resolved rejected,
process = special ?
mightThrow :
function() {
try{
mightThrow()
} catch( e ) {
if ( jQuery.Deferred.exceptionHook ) {
//
jQuery.Deferred.exceptionHook( e, process.stackTrace )
}
//
if ( depth + 1 >= maxDepth ) {
if ( handler !== Thrower ) {
that = undefined;
args = [ e ];
}
// , reject
// >= maxDepth
deferred.rejectWith( that, args );
}
}
};
// depth 0, process
if ( depth ) {
process();
} else {
if ( jQuery.Deferred.getStackHook ) {
process.strackTrace = jQuery.Deferred.getStackHook();
}
//
window.setTimeout( process );
}
};
}
resolveの深さについては、いくつかの例を挙げます.
let defer = $.Deferred();
let defer2 = $.Deferred();
let newDefer = defer.then(
function() {
console.log( 'defer resolved' )
return defer2;
},
function() {
console.log( 'defer rejected' )
},
function() {
console.log( 'defer notified ')
}
)
// defer resolve ,
// 0 defer
// 1
// :defer is resolved
defer.resolve();
// 0, maxDepth = 1,
//
// :defer onProgress defer.resolve()
// newDefer onProgress depth
defer.notify();
// newDefer defer2, newDefer onProgress
// :newDefer is notified
defer2.notify();
let defer3 = $.Deferred();
// ,defer2 defer3, , maxDepth = 2
// newDefer defer3
defer2.resolve( defer3 );
// defer2
// depth = 1 < maxDepth,
//
defer2.notify()
// defer3 , newDefer fulfilled
// :newDefer is resolved
defer3.resolve()
まとめ:
ここではjQuery.eachはtuplesをpromiseとdeferredに注入する
ソースとコメントを直接見ればいいです.
jQuery.each( tuples, function( i, tuple ) {
// list done、fail、progress
var list = tuple[ 2 ],
//
stateString = tuple[ 5 ];
// done、fail、progress
promise[ tuple[ 1 ] ] = list.add;
//
if ( stateString ) {
list.add(
//
function() {
state = stateString;
},
// (done、fail、progress)
tuples[ 3 - i ][ 2 ].disable,
// then
tuples[ 3 - i ][ 3 ].disable,
// progress
tuples[ 0 ][ 2 ].lock,
tuples[ 0 ][ 3 ].lock
);
}
// then fire [ done, fail, progress ]
// then onDone、onFail、onProgress
list.add( tuple[ 3 ].fire );
// deferred , this
deferred[ tuple[ 0 ] ] = function() {
deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
return this;
};
// deferred
deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
} );
最后に:私もちょうどjQueryのソースコードを学ぶことを始めて、この文はただノートと心得と分かち合うことを学ぶだけとして、Deferredについて、まだ多くの理解しない地方があって、各位の大きい人の指导を歓迎します