jquery中的工具方法--Deferred和when
2016-06-06 14:41
507 查看
在jquery1.5版本以后,Deferred和promise就是jquery中非常常用的两个功能,并且在这个版本利用Deferred又完全重写了ajax模块。Deferred对象是有jquery.Deferred构造的,$.Deferred在jquery代码中,分别在promise方法、Dom ready、ajax模块、动画模块被使用
这里需要说明一下deferred和promise的区别,deferred相当于promise的继承类,相比于promise方法,deferred可以通过resolve、reject和 notify改变回调的状态,而promise不能修改回调的状态
deferred.done(doneCallbacks[,doneCallbacks]):添加成功回调函数,当异步队列处于成功状态时被调用
deferred.fail(failCallbcks[,failCallbacks]): 添加失败回调函数,当异步队列处于失败状态时被触发
deferred.progress(progressCallbacks):添加消息回调函数
deferred.then(doneCallbacks,failCallbacks[,progressCallbacks]): 添加成功回调函数、失败回调函数、消息回调函数
deferred.always(alwaysCallbacks[,alwaysCallbacks]):添加回调函数,当异步队列处于成功或失败状态时调用
执行回调函数方法
deferred.resolve(args): 使用指定的参数调用所有的成功回调函数
deferred.resolveWith(context[,args]): 使用指定的上下文和参数调用所有的成功回调函数,异步队列进入成功状态
deferred.reject(args): 使用指定的参数调用所有失败回调函数,异步队列进入失败状态
deferred.rejectWith(context[.args]: 使用指定的上下文和参数调用所有失败回调函数,异步对垒进入失败状态
deferred.notify(args): 使用指定的参数调用所有的消息回调函数
deferred.notifyWith(context[,args]):使用指定的上下文和参数调用所有的消息回调函数
判断当前状态
deferred.state():判断异步队列的当前状态
工具
deferred.pipe(
deferred.promise([target]):返回当前Deferred对象的制度副本,或者为普通对象增加异步队列的功能
创建三个$.Callbacks对象,分别表示函数执行的三个状态,即未完成、完成和失败,并设置初始状态为待定(pending)
创建异步队列的只读副本promise,其中包含了方法done() 、fail()、progress()、state()、isRejected()、then()、always()、pipe()、promise()
定义异步队列deferred
a. 把只读副本promise中的方法添加到异步队列deferred中
b. 为异步队列deferred添加触发执行成功、失败、消息回调函数的方法,包括resolve()、resolveWith()、reject()、rejectWith()、notify()、notifyWith()
c. 为异步队列deferred添加设置状态的回调函数
如果传入函数参数func,则调用。
返回异步队列deferred
$.when方法中,只有参数中的所有函数都为resolve时,才执行done操作,只要有一个为reject,立即执行fail操作
返回值为Deferred对象和非Deferred对象混杂时,对于非Deferred对象的计数器减一
当所传参数中所有的Deferred对象都resolve后,执行回调
// Deferred helper
when: function( subordinate /* , …, subordinateN */ ) {
var i = 0,
resolveValues = slice.call( arguments ),//将arguments变为数组
length = resolveValues.length,
Deferred的用法
var defer = $.Deferred(); function aaa(){ console.log("aaa"); defer.resolve();//完成态 相当于callbacks中的fire } aaa(); //相当于callbacks中的add方法 通过done改变状态 defer.done(function(){ console.log('success'); }); var defer = $.Deferred(); function runAsync(){ setTimeout(function(){ console.log('执行完成'); defer.resolve('data'); },2000) return defer.promise(); } defer.done(function(data){ console.log(data); }) defer.fail(function(data){ console.log(data); }) var d = runAsync(); d.done(function(data){ console.log(data); }) d.then(function(data){ console.log(data); })
这里需要说明一下deferred和promise的区别,deferred相当于promise的继承类,相比于promise方法,deferred可以通过resolve、reject和 notify改变回调的状态,而promise不能修改回调的状态
$.Deferred的实现
异步队列的方法
添加回调函数方法deferred.done(doneCallbacks[,doneCallbacks]):添加成功回调函数,当异步队列处于成功状态时被调用
deferred.fail(failCallbcks[,failCallbacks]): 添加失败回调函数,当异步队列处于失败状态时被触发
deferred.progress(progressCallbacks):添加消息回调函数
deferred.then(doneCallbacks,failCallbacks[,progressCallbacks]): 添加成功回调函数、失败回调函数、消息回调函数
deferred.always(alwaysCallbacks[,alwaysCallbacks]):添加回调函数,当异步队列处于成功或失败状态时调用
执行回调函数方法
deferred.resolve(args): 使用指定的参数调用所有的成功回调函数
deferred.resolveWith(context[,args]): 使用指定的上下文和参数调用所有的成功回调函数,异步队列进入成功状态
deferred.reject(args): 使用指定的参数调用所有失败回调函数,异步队列进入失败状态
deferred.rejectWith(context[.args]: 使用指定的上下文和参数调用所有失败回调函数,异步对垒进入失败状态
deferred.notify(args): 使用指定的参数调用所有的消息回调函数
deferred.notifyWith(context[,args]):使用指定的上下文和参数调用所有的消息回调函数
判断当前状态
deferred.state():判断异步队列的当前状态
工具
deferred.pipe(
[doneFilter]
[,failFilter]
[,progressFilter]): 返回一个新的异步队列的只读副本,通过过滤函数过滤当期那异步队列的状态和值
deferred.promise([target]):返回当前Deferred对象的制度副本,或者为普通对象增加异步队列的功能
实现过程
方法jQuery.Deferred(func)创建异步队列的5个关键步骤如下创建三个$.Callbacks对象,分别表示函数执行的三个状态,即未完成、完成和失败,并设置初始状态为待定(pending)
创建异步队列的只读副本promise,其中包含了方法done() 、fail()、progress()、state()、isRejected()、then()、always()、pipe()、promise()
定义异步队列deferred
a. 把只读副本promise中的方法添加到异步队列deferred中
b. 为异步队列deferred添加触发执行成功、失败、消息回调函数的方法,包括resolve()、resolveWith()、reject()、rejectWith()、notify()、notifyWith()
c. 为异步队列deferred添加设置状态的回调函数
如果传入函数参数func,则调用。
返回异步队列deferred
// 扩展了工具方法Deferred和when // $.Deferred(); // $.when() // 延迟对象是基于callbacks对象实现的 // 实现了对异步的的统一管理 // 提供了always then promise pipe when 等实用的方法 jQuery.extend({ Deferred: function( func ) { var tuples = [ // action, add listener, listener list, final state // 分别对应完成态 失败态和未完成态 // resolve相当于callbacks对象中的fire方法 done相当于add方法 resolved为状态 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], [ "notify", "progress", jQuery.Callbacks("memory") ] ], state = "pending", promise = { // 该方法返回当前的状态 state: function() { return state; }, //完成态和失败态都执行该操作 always: function() { deferred.done( arguments ).fail( arguments ); return this; }, //then方法同时绑定完成态、失败态和未完成态三个回调函数 then: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; return jQuery.Deferred(function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for forwarding actions to newDefer // 对各个状态添加回调函数 deferred[ tuple[1] ](function() { var returned = fn && fn.apply( this, arguments ); //确定回调函数的返回值 if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .done( newDefer.resolve ) .fail( newDefer.reject ) .progress( newDefer.notify ); } else { newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); } }); }); fns = null; }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Keep pipe for back-compat promise.pipe = promise.then; // Add list-specific methods // 对映射数组进行遍历操作 jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ],//callback回调 stateString = tuple[ 3 ];//状态字符串 // promise[ done | fail | progress ] = list.add // 对done、fail和progress等同于list.add方法 并将添加回调的方法添加至promise对象中 promise[ tuple[1] ] = list.add; // Handle state // 只有完成态和失败态有statestring if ( stateString ) { list.add(function() { // state = [ resolved | rejected ] state = stateString; //当完成态的回调被调用时 失败态和进行态就不能被调用 //i^1为位运算符 当i为1时 结果为0,当i为0时 结果为1 // [ reject_list | resolve_list ].disable; progress_list.lock }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); } // deferred[ resolve | reject | notify ] deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); return this; }; deferred[ tuple[0] + "With" ] = list.fireWith; }); // Make the deferred a promise // 将promise和deferred合并 promise.promise( deferred ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; },
$.when()的用法
$.when方法实现多个回调函数的控制function aaa(){ var defer = $.Deferred(); defer.resolve(); return defer; } function bbb(){ var defer = $.Deferred(); defer.resolve(); return defer; } //需求:当两个回调都成功的时候执行操作 //when主要是针对多延迟对象的操作 $.when(aaa(),bbb()).done(function(){ alert('成功'); }).fail(function(){ alert('失败'); })
$.when方法中,只有参数中的所有函数都为resolve时,才执行done操作,只要有一个为reject,立即执行fail操作
$.when的实现
接收若干个对象,参数仅一个且返回值不是Deferred对象将立即执行回调函数返回值为Deferred对象和非Deferred对象混杂时,对于非Deferred对象的计数器减一
当所传参数中所有的Deferred对象都resolve后,执行回调
// Deferred helper
when: function( subordinate /* , …, subordinateN */ ) {
var i = 0,
resolveValues = slice.call( arguments ),//将arguments变为数组
length = resolveValues.length,
// the count of uncompleted subordinates // 记录未完成态的回调函数的个数 // 当传入的参数为0或传入的参数的返回值不是延迟对象的时候 length为0; remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that. // 若只有一个参数,延迟对象即为传入的参数 // 若没有参数或参数大于1 创建新的延迟对象 deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values // 更新计数器 updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( values === progressValues ) { deferred.notifyWith( contexts, values ); //当计数器减为0时 执行resolve } else if ( !(--remaining) ) { deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved if ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); resolveContexts = new Array( length ); for ( ; i < length; i++ ) { if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject )//只要有一个失败 触发reject .progress( updateFunc( i, progressContexts, progressValues ) ); } else { //当参数的返回值不是延迟对象 对remaining减1 --remaining; } } } // if we're not waiting on anything, resolve the master // 针对没有参数或都是完成态的情况 if ( !remaining ) { deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } });
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- JavaScript演示排序算法
- 2015-2016网页设计趋势分析 Web Design of Trends
- jQuery Ajax 跨域调用
- 移动端的长按事件
- jquery教程靠边站,一分钱不花让你免费学会jquery
- JQuery+Strusts1.x无刷新登录
- $.ajax()方法详解
- jQuery ajax - ajax() 方法
- JavaScript 各种遍历方式详解
- 数组方法汇总
- jQuery Html控件基本操作(日常收集整理)
- jQuery插件实现文字无缝向上滚动效果代码
- jQuery菜单插件用法实例
- JQuery 初体验(建议学习jquery)
- 基于Jquery和CSS3制作数字时钟附源码下载(CSS3篇)
- Jquery实现的table最后一行添加样式的代码
- jQuery实现向下滑出的平滑下拉菜单效果
- jQuery 练习[一] 学习jquery的准备工作
- jquery获得页面元素的坐标值实现思路及代码