经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » jQuery » 查看文章
jQuery源码分析(九) 异步队列模块 Deferred 详解
来源:cnblogs  作者:大沙漠  时间:2019/10/12 9:18:59  对本文有异议

deferred对象就是jQuery的回调函数解决方案,它解决了如何处理耗时操作的问题,比如一些Ajax操作,动画操作等。(P.s:紧跟上一节:https://www.cnblogs.com/greatdesert/p/11433365.html的内容)

异步队列有三种状态:待定(pending)、成功(resolved)和失败(rejected),初始时处于pending状态

我们可以使用jQuery.Deferred创建一个异步队列,返回一个对象,该对象含有如下操作:

  done(fn/arr)                     ;添加成功回调函数,当异步队列处于成功状态时被调用,参数同:jQuery.Callbacks(flags).add(fn/arr)
  fail(fn/arr)                           ;添加失败回调函数,参数同上
  progress(fn/arr)                         ;添加消息回调函数,参数同上
  then(donefn/arr,failfn/arr,profn/arr)     ;同时添加成功回调函数、失败回调函数和消息回调函数
  always(fn/arr)                       ;添加回调函数到doneList和failList中,即保存两份引用,当异步队列处于成功或失败状态时被调用    ;参数可以是函数、函数列表
  state()                                  ;返回异步队列的当前状态、返回pending、resolved或者rejected
  promise(obj)                           ;如果设置了obj参数对象则为obj对象增加异步队列的方法并返回。如果未设置参数obj,则返回当前Deferred对象的只读副本

如果调用$.Diferred()创建一个异步队列,返回后的对象可以调用如下几个方法:

 writer by:大沙漠 QQ:22969969

  resolve(args)                      ;使用指定的参数调用所有的成功回调函数,异步队列进入成功状态,之后就无法再调用
  reject(args)                           ;使用指定的参数调用所有的失败回调函数,异步队列进入失败状态
  notify(args)                              ;使用指定的参数调用所有的消息回调函数
  resolveWith(context,args)               ;使用指定的上下文和参数调用所有的成功回调函数,异步队列进入成功状态
  rejectWith(context,args)               ;使用指定的上下文和参数调用所有的失败回调函数,异步队列进入失败状态
  notifyWith(context,args)               ;使用指定的上下文和参数调用所有的消息回调函数

是不是和上一节介绍的Callbacks的fire和fireWith很像,Defferred内部就是通过通过Callback()回调函数列表来实现的,例如:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <script src="http://libs.baidu.com/jquery/1.7.1/jquery.js"></script>
  7. </head>
  8. <body>
  9. <script>
  10. function f1(x){console.log('f1 '+x);}
  11. function f2(x){console.log('f2 '+x);}
  12. function f3(x){console.log('f3 '+x);}
  13. var t = $.Deferred(); //创建异步队列
  14. t.done(f1).fail(f2).progress(f3); //添加成功回调函数、失败回调函数和消息列表回调函数。等同于t.then(f1,f2,f3);
  15. t.notify('test'); //触发所有消息函数列表,输出:f3 test
  16. t.resolve('done'); //触发所有成功回调函数,输出:done
  17. t.reject('fail'); //没有输出,触发成功回调函数后失败回调函数列表就会被禁用,反过来也如此
  18. t.progress(f1); //输出:f1 test。这是因为消息回调函数之前已经被调用过,保存了上下文和参数了,如果之前没有调用,这里就没有输出。
  19. </script>
  20. </body>
  21. </html>

输出如下:

 

源码分析


异步队列内部的实现原理就是通过jQuery.Callbacks定义三个回调函数列表,分别存储成功、失败、消息回调函数,然后返回一个对象,在该对象上设置done、fail和progress,分别对应这三个回调函数列表的add方法,这样就实现分别添加不同状态的回调函数了

$.Deferred是通过jQuery.extend函数直接挂载到jQuery里的,结构如下:

  1. jQuery.extend({
  2. Deferred: function( func ) {
  3. var doneList = jQuery.Callbacks( "once memory" ), //成功回调函数列表
  4. failList = jQuery.Callbacks( "once memory" ), //失败回调函数列表
  5. progressList = jQuery.Callbacks( "memory" ), //消息回调函数列表  ;这三个回调函数列表就是存储我们添加的触发函数的
  6. state = "pending", //初始状态:pending
  7. lists = { //后面的方法会遍历变量list中的属性名来为异步队列添加方法deffred.resolve()、resolveWith()、reject()、rejectWith()、notify()和notifyWith()
  8. resolve: doneList,
  9. reject: failList,
  10. notify: progressList
  11. },
  12. promise = { //异步队列的只读副本
  13. /**/
  14. },
  15. deferred = promise.promise({}), //异步队列
  16. key;
  17. for ( key in lists ) { //添加触发成功、失败、消息回调函数的方法,执行后deferred对象就多了resolve()、resolveWith()、reject()、rejectWith()、notify()和notifyWith()方法。
  18. deferred[ key ] = lists[ key ].fire;
  19. deferred[ key + "With" ] = lists[ key ].fireWith;
  20. }
  21. // Handle state
  22. deferred.done( function() { //添加三个成功回调函数,分别用于设置状态为成功(resolved),禁用失败列表函数列表和锁定消息回调函数列表
  23. state = "resolved";
  24. }, failList.disable, progressList.lock ).fail( function() { //添加三个失败回调韩素,分别用于设置状态为失败(rejected),禁用成功列表函数列表和锁定消息回调函数列表
  25. state = "rejected";
  26. }, doneList.disable, progressList.lock );
  27. // Call given func if any
  28. if ( func ) {
  29. func.call( deferred, deferred );
  30. }
  31. // All done!
  32. return deferred; //返回异步队列deffrred
  33. },
  34. //...
  35. })

可以看到$.Deferred最后返回的是deferred这个布局变量,而deferred是promise.promise({})的返回值,我们来看看promise的实现方法:

  1. promise = { //异步队列的只读副本
  2. done: doneList.add, //添加成功回调函数,引用对应的回调函数列表的callbacks.add(fn/arr)方法,下同
  3. fail: failList.add, //添加失败回调函数
  4. progress: progressList.add, //添加消息回调函数
  5. state: function() { //返回异步队列的当前状态:pending、resolved、rejected之一
  6. return state;
  7. },
  8. // Deprecated
  9. isResolved: doneList.fired,
  10. isRejected: failList.fired,
  11. then: function( doneCallbacks, failCallbacks, progressCallbacks ) { //同时添加成功回调函数、失败回调函数和消息回调函数
  12. deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
  13. return this;
  14. },
  15. always: function() { //添加回调函数到doneList和failList中,即保存两份引用,当异步队列处于成功或失败状态时被调用
  16. deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
  17. return this;
  18. },
  19. pipe: function( fnDone, fnFail, fnProgress ) { //过滤当前异步队列的状态和参数,并返回一个新的异步队列的副本,一般用不到
  20. return jQuery.Deferred(function( newDefer ) {
  21. jQuery.each( {
  22. done: [ fnDone, "resolve" ],
  23. fail: [ fnFail, "reject" ],
  24. progress: [ fnProgress, "notify" ]
  25. }, function( handler, data ) {
  26. var fn = data[ 0 ],
  27. action = data[ 1 ],
  28. returned;
  29. if ( jQuery.isFunction( fn ) ) {
  30. deferred[ handler ](function() {
  31. returned = fn.apply( this, arguments );
  32. if ( returned && jQuery.isFunction( returned.promise ) ) {
  33. returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
  34. } else {
  35. newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
  36. }
  37. });
  38. } else {
  39. deferred[ handler ]( newDefer[ action ] );
  40. }
  41. });
  42. }).promise();
  43. },
  44. // Get a promise for this deferred
  45. // If obj is provided, the promise aspect is added to the object
  46. promise: function( obj ) { //如果设置了obj参数对象则为obj对象增加异步队列的方法并返回。如果未设置参数obj,则返回当前Deferred对象的只读副本,
  47. if ( obj == null ) { //如果obj为空
  48. obj = promise; //则返回promise对象(是上一层作用域链的promise对象)
  49. } else {
  50. for ( var key in promise ) { //否则遍历promise
  51. obj[ key ] = promise[ key ]; //将promise的所有方法、属性保存到obj中
  52. }
  53. }
  54. return obj; //最后返回obj
  55. }
  56. },

$.Deferred就是对Callbacks回调函数列表的管理而已,产生了一个新的$.Defferred接口,内部添加了一个state表示异步队列的状态。

原文链接:http://www.cnblogs.com/greatdesert/p/11454359.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号