看一个实例(纯属胡扯,不要当真)。我们需要从间谍卫星返回的数据用不同的算法来进行解析,如果解析结果信号强度大于90%,则证明该数据有效,可以被解析;如果强度小于10%,则证明只是宇宙噪音;否则,证明数据可能有效,换一种算法解析:
// 我们封装Deferred产生一个promise对象,其不能被外部手动解析,只能内部确定最终状态 asynPromise = function () { let d = $.Deferred(); (function timer() { setTimeout(function () { // 产生随机数,代替解析结果,来确定本次的状态 let num = Math.random(); if (num > 0.9) { d.resolve(); // 解析成功 } else if (num < 0.1) { d.reject(); // 解析失败 } else { d.notify(); // 解析过程中 } setTimeout(timer, 1000); // 持续不断的解析数据 }, 1000); })(); // 如果不返回promise对象,则可以被外部手动调整解析状态 return d.promise(); }; // then方法的三个参数分别代表完成、失败、过程中的回调函数 asynPromise().then(function () { console.log('resolve success'); }, function () { console.log('reject fail'); }, function () { console.log('notify progress'); }); // 本地执行结果(每个人的不一样,随机分布,但最后一个一定是success或fail) notify progress notify progress notify progress notify progress notify progress reject fail // 后面不会再有输出,因为一旦解析状态为success或fail,则不会再改变除了上面的主要功能,还提供了notifyWith/resolveWith/rejectWith/state辅助方法。
其所有的源码实现和注释为:
Deferred: function( func ) { var tuples = [ // action, add listener, callbacks, // ... .then handlers, argument index, [final state] // 用于后面进行第一个参数绑定调用第二个参数,第三个和第四个参数分别是其不同的回调函数队列 [ "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" ] ], state = "pending", promise = { state: function() { return state; }, // 同时添加done和fail句柄 always: function() { deferred.done( arguments ).fail( arguments ); return this; }, "catch": function( fn ) { return promise.then( null, fn ); }, then: function( onFulfilled, onRejected, onProgress ) { var maxDepth = 0; function resolve( depth, deferred, handler, special ) { return function() { var that = this, args = arguments, mightThrow = function() { var returned, then; // Support: Promises/A+ section 2.3.3.3.3 // // Ignore double-resolution attempts if ( depth < maxDepth ) { return; } returned = handler.apply( that, args ); // Support: Promises/A+ section 2.3.1 // if ( returned === deferred.promise() ) { throw new TypeError( "Thenable self-resolution" ); } // Support: Promises/A+ sections 2.3.3.1, 3.5 // // // Retrieve `then` only once then = returned && // Support: Promises/A+ section 2.3.4 // // Only check objects and functions for thenability ( typeof returned === "object" || typeof returned === "function" ) && returned.then; // Handle a returned thenable if ( jQuery.isFunction( then ) ) { // Special processors (notify) just wait for resolution if ( special ) { then.call( returned, resolve( maxDepth, deferred, Identity, special ), resolve( maxDepth, deferred, Thrower, special ) ); // Normal processors (resolve) also hook into progress } else { // ...and disregard older resolution values maxDepth++; then.call( returned, resolve( maxDepth, deferred, Identity, special ), resolve( maxDepth, deferred, Thrower, special ), resolve( maxDepth, deferred, Identity, deferred.notifyWith ) ); } // Handle all other returned values } else { // Only substitute handlers pass on context // and multiple values (non-spec behavior) if ( handler !== Identity ) { that = undefined; args = [ returned ]; } // Process the value(s) // Default process is resolve ( special || deferred.resolveWith )( that, args ); } }, // Only normal processors (resolve) catch and reject exceptions // 只有普通的process能处理异常,其余的要进行捕获,这里不是特别明白,应该是因为没有改最终的状态吧 process = special ? mightThrow : function() { try { mightThrow(); } catch ( e ) { if ( jQuery.Deferred.exceptionHook ) { jQuery.Deferred.exceptionHook( e, process.stackTrace ); } // Support: Promises/A+ section 2.3.3.3.4.1 // // Ignore post-resolution exceptions if ( depth + 1 >= maxDepth ) { // Only substitute handlers pass on context // and multiple values (non-spec behavior) if ( handler !== Thrower ) { that = undefined; args = [ e ]; } deferred.rejectWith( that, args ); } } }; // Support: Promises/A+ section 2.3.3.3.1 // // Re-resolve promises immediately to dodge false rejection from // subsequent errors if ( depth ) { process(); } else { // Call an optional hook to record the stack, in case of exception // since it's otherwise lost when execution goes async if ( jQuery.Deferred.getStackHook ) { process.stackTrace = jQuery.Deferred.getStackHook(); } window.setTimeout( process ); } }; } return jQuery.Deferred( function( newDefer ) { // progress_handlers.add( ... ) tuples[ 0 ][ 3 ].add( resolve( 0, newDefer, jQuery.isFunction( onProgress ) ? onProgress : Identity, newDefer.notifyWith ) ); // fulfilled_handlers.add( ... ) tuples[ 1 ][ 3 ].add( resolve( 0, newDefer, jQuery.isFunction( onFulfilled ) ? onFulfilled : Identity ) ); // rejected_handlers.add( ... ) tuples[ 2 ][ 3 ].add( resolve( 0, newDefer, jQuery.isFunction( onRejected ) ? onRejected : Thrower ) ); } ).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object // 通过该promise对象返回一个新的扩展promise对象或自身 promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Add list-specific methods // 给promise添加done/fail/progress事件,并添加互相的影响关系,并为deferred对象添加3个事件函数notify/resolve/reject jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ], stateString = tuple[ 5 ]; // promise.progress = list.add // promise.done = list.add // promise.fail = list.add promise[ tuple[ 1 ] ] = list.add; // Handle state // 只有done和fail有resolved和rejected状态字段,给两个事件添加回调,禁止再次done或者fail,锁住progress不允许执行回调 if ( stateString ) { list.add( function() { // state = "resolved" (i.e., fulfilled) // state = "rejected" state = stateString; }, // rejected_callbacks.disable // fulfilled_callbacks.disable tuples[ 3 - i ][ 2 ].disable, // progress_callbacks.lock tuples[ 0 ][ 2 ].lock ); } // progress_handlers.fire // fulfilled_handlers.fire // rejected_handlers.fire // 执行第二个回调列表 list.add( tuple[ 3 ].fire ); // deferred.notify = function() { deferred.notifyWith(...) } // deferred.resolve = function() { deferred.resolveWith(...) } // deferred.reject = function() { deferred.rejectWith(...) } // 绑定notify/resolve/reject的事件,实际执行的函数体为加入上下文的With函数 deferred[ tuple[ 0 ] ] = function() { deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); return this; }; // deferred.notifyWith = list.fireWith // deferred.resolveWith = list.fireWith // deferred.rejectWith = list.fireWith deferred[ tuple[ 0 ] + "With" ] = list.fireWith; } ); // Make the deferred a promise // 将deferred扩展为一个promise对象 promise.promise( deferred ); // Call given func if any // 在创建前执行传入的回调函数进行修改 if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; },jQuery.when方法