1. callbacks使用方法

  2. callbacks原理分析

  3. deferred概念 及 使用方法

  4. deferred原理分析

callbacks

$.callbacks用于管理函数队列
通过add添加处理函数到队列当中,通过fire去执行这些处理函数
ps:$.callbacks是在jq内部的使用的,如.ajax, $.Defferred等组件提供基础功能的函数。它也可以用在自己开发的插件中。

使用方法:

通过字符串参数的形式,支持4种特定的功能:

  • Once: 队列中只执行一次
  • unique:添加的函数必须是唯一的,不能重复
  • stopOnFalse:内部队列的函数是依次执行的,当某个函数的返回值是false,停止继续执行剩下的函数
  • memory:fire一次后,内部会记录fire的参数,下次add的时候,会把记录的参数传递给新加的函数,立即执行这个新添加的函数。
// html:
var cb = _.callbacks('memory')
cb.add(function () {        // add向内部队列中添加处理函数console.log(1)})cb.add(function () {console.log(3)}) cb.fire()                    // 一次执行队列中的函数cb.add(function () {console.log(2)})
// 运行结果: 1  3  2// 不加参数
var cb1 = _.callbacks()
cb1.add(function () {       console.log(1)return false}, function () {}console.log(2))// 结果:1 2// 加stopOnFalse参数
var cb1 = _.callbacks(‘stopOnFalse’)
cb1.add(function () {       console.log(1)return false}, function () {}console.log(2))// 结果:1

toString.call(fn) 类型的检索, 返回[object function], 若为1,返回[object number]

原理分析:

/*   callbacks:调用fire:  执行_.callbacks().fire(), _.callbacks().add()若memory= true时执行fire()调用add:   执行_.callbacks().add()once判断:  fire()之前判断,若once = true,则不调用memory判断: fire()时记录当前参数,add的时候执行fire,把fire(memory)unique判断:  add()之前,判断队列中是否存在该函数,若有,则不push到队列中,没有则push进去stopOnFalse: fire执行时,若队列中当前执行的函数返回为false,则break出来*/(function (root) {var optionsCache = {}var _ = {callbacks: function (options) {options = typeof options === 'string' ? (optionsCache[options] || createOptions(options)) : {};var list = []; // 该数组即为所谓的队列,当会赋予它一些功能var index, length, testings, memory, start, starts;       // index 执行位置// 真正处理的var fire = function (data) {// 执行memory = options.memory && dataindex = starts || 0start = 0 testings = truelength = list.length// 执行整个处理函数 for (; index < length; index++) {// apply 绑定上下文对象 ,data [context, arguments]if (list[index].apply(data[0], data[1]) === false && options.stopOnfalse) { break;}}}var self = {add: function () {// 类数组转化为数组,并且内部要判断是否为函数var args = Array.prototype.slice.call(arguments)// 记录添加前的长度start = list.lengthargs.forEach(function (fn) {if (toString.call(fn) === '[object Function]') {  // 检测类型list.push(fn)}})// 设置了memory需要starts,否则add 2次的时候会,start其实会少一次if (memory) {starts = startfire(memory)}},// 上下文绑定,执行处理函数,除了要传参,还要控制执行过程中上下文的绑定fireWith: function (context, arguments) {var args = [context, arguments]// 如果没有配置once,则会继续执行 && 第一次调用的时候也要执行if (!options.once || !testings) {fire(args)}},// fire不是api中解读的fire,是处理参数的fire: function () {self.fireWith(this, arguments)}}// 因为每次调用callbacks都会返回一个队列,队列里有add fire操作return self},deferred: function (func) {}}function createOptions (options) {var object = optionsCache[options] = {}// 传两个参数 - 综合的使用_.callbacks('once memory')options.split(/\s+/).forEach(function (value) {object[value] = true})return object}root._ = _
})(this)

Deferred

概念及使用方法:

Promise作为一个模型,提供了一个在软件工程中描述掩饰(或将来)概念的解决方案。

  1. promise表示一个异步操作的最终结果。
  2. 与promise最主要的交互方法是,通过将函数传入它的then方法,从而获取得promise最终的值或promise最终拒绝(reject)的原因。
  3. 一个promise必须处于以下状态的其中之一: pending fulfilled或rejected
  4. 一个promise必须提供一个then方法来获取其值或原因
    而deferred是这种规范的具体实现。

promise/A+规范:通过一组API来规范异步操作,这样也能让异步操作的流程控制更加容易
状态:resolved、rejected:then方法接受两个参数:一个用于promise得到解决resolved,一个用于promise拒绝rejected
初始创建时是默认状态,状态只能从默认变成完成|失败,一旦完成或失败状态就不能再改变了。

jQuery.Deferred():
一个构造函数,返回一个链式使用对象方法来注册多个回调,回调列表,调用回调列表,并转达任何同步或异步函数的成功或失败状态。deferred.done()
当deferred(延迟)对象解决时,调用添加处理程序deferred.fail()
当deferred(延迟)对象拒绝时,调用添加处理程序deferred.progress()
当deferred(延迟)生成进度通知时,调用(已)添加的处理程序jQuery.when()
提供一种方法来执行一个或多个对象的回调函数,Deferred(延迟)对象通常表示异步事件。.promise()
返回一个promise对象用来观察当某种类型的所有行动绑定到集合,排队与否还是已经完成。
// html测试文件:
<script>// 延迟对象事例一:var wait = function () {var der = $.Deferred()       // 延迟对象var test = function () {console.log('事例一')der.resolve('事例一test过')       // 调用成功队列中的处理函数 }setTimeout(test, 2000)return der                       // 返回延时对象}// 延迟对象的状态,决定调用哪个队列的处理函数$.when(wait())        .done(function(name) {          // 调用promise的done方法  即self.add() 往成功的队列中添加处理函数 console.log(name)console.log('执行成功')}).fail(function() {console.log('执行失败')})// 事例二// 不要when方法:var wait1 = function (src) {var der1 = $.Deferred()     // 延迟对象var img = document.getElementsByTagName('img')[0]img.onload = function () {der.resolve('加载成功') }img.src = srcreturn der.promise()}// then方法返回的是新的deferred对象 ,支持链式调用,// then 的回调多个的话,第一个回调执行完后返回的值作为第二个函数的参数,依此类推// then方法后最多可以传3个参数,成功 失败 进行中...wait('index.jpg').then(() => {var der = jQuery.Deferred()der.resolve('又是一个deferred')return der.promise( )}).then(() => {})// 上面这个 wait 方法块里有3个延迟对象// wait('index.jpg') 一个// 第一个 .then 产生一个// 第二个 .then 产生一个
</script>

原理分析:

/* 1、队列list ,用 jQuery.Callbacks(~ ) 创建三个队列,有add() fire()方法2、给promise三个状态,promise.done,promise.fail,promise.progress = list ,往promiss扩展3、改变状态,成功,失败才有,添加第一个处理程序,state = stateString =tuple[5]4、deferred扩展resolve = function (){deferred.resolveWith(~)}notify = function (){deferred.notifyWith(~)}reject = function (){deferred.rejectWith(~)}5、定义deferred.rejectWith,notifyWith,resolveWith = list.add6、把promise扩展到deferred7、执行__.Deferred(func) 传来的func8、promise.then后,new jQuery.Deferred(){tuple循环,添加funs数组中,将传来的类数组转化为数组添加,deferred[tuple[1]] 即deferred.done,fail,progress 从promise中扩展过来的}*/
jQuery.extend( {Deferred: function( func ) {var tuples = [// action, add listener, callbacks,// 状态 往队列中添加处理函数的方式 创建队列 最终状态信息的描述[ "resolve", "done", jQuery.Callbacks( "once memory" ),jQuery.Callbacks( "once memory" ), 0, "resolved" ],[ "reject", "fail", jQuery.Callbacks( "once memory" ),jQuery.Callbacks( "once memory" ), 1, "rejected" ],[ "notify", "progress", jQuery.Callbacks( "memory" ),jQuery.Callbacks( "memory" ), 2 ],],state = "pending",promise = {state: function() {return state;},// Keep pipe for back-compatthen: function( /* onFulfilled, onRejected, onProgress */) { var fns = [].slice.call(arguments)     // 将参数类数组 转化为 数组// 返回 promise 对象return new jQuery.Deferred(function (newDeferred) {// 所有逻辑会在这个函数中处理 tuples.forEach(function (tuple, i) {var fn = jQuery.isFunction(fns[i]) && fns [i]/*   通过闭包去访问的,指的是此处链接调用的deferred ,即调用wait所创出来的对象newDeferred 通过参数传递,指向新创建的deferred 对象*/// 往当前对应的延迟对象队列中添加callbackdeferred[tuple[1]](function () {                            // this 指向当前遍历的这项成员,tuples这个数组,arguments调用callbacks的时候有没有传参var returnDeferred = fn && fn.apply(this, arguments)if (returnDeferred && jQuery.isFunction(returnDeferred.promise)) {// 返回的又是一个promise对象, 把后面的callback放到队列中returnDeferred.done(newDeferred.resolve).fail(newDeferred.reject).progress(newDeferred.notify)}})})}).promise()},// Get a promise for this deferred// If obj is provided, the promise aspect is added to the objectpromise: function( obj ) {return obj != null ? jQuery.extend( obj, promise ) : promise;}},// 延迟对象  关心属性 方法deferred = {};    // [resolve | reject | notify | state | then | promise ]// Add list-specific methods jQuery.each( tuples, function( i, tuple ) {var list = tuple[ 2 ],         // 创建队列 =》会创建3次 self 对象的引用,即list具有add fire fireWith功能stateString = tuple[ 5  ];   // 获取到当前状态信息的描述,只有成功和失败有 // promise.progress = list.add 当延迟对象解决时// promise.done = list.add     当延迟对象拒绝时// promise.fail = list.add     当延迟对象生成进度通知时promise[ tuple[ 1 ] ] = list.add;  // 对promise进行扩展 , 往对应的队列里面添加处理函数// Handle state,当状态为成功或失败时,即为resolve或reject时(第三个无值)if ( stateString ) {  // 添加第一个处理程序 (成功或失败才会添加)list.add(function() {// state = "resolved" (i.e., fulfilled)// state = "rejected"state = stateString;},);}// deferred.notify = function() { deferred.notifyWith(...) }// deferred.resolve = function() { deferred.resolveWith(...) }// deferred.reject = function() { deferred.rejectWith(...) }// 延迟对象的权限: 去绑定状态// 如果this = deferred, 说明可以去改变当前的状态,最糟的是有多个callback,去修改掉了callback的状态,那该程序就毁了// 所以要严格要求,给promise,只有add权限,即只有往队列添加callback的权限,查看权限deferred[ tuple[ 0 ] ] = function() {deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments );return this;};// 执行队列,调用队列中的处理函数,并且给他们传参,绑定执行时上下文对象 this === deferred ? promise : this  // deferred.notifyWith = list.fireWith   // deferred.resolveWith = list.fireWith// deferred.rejectWith = list.fireWithdeferred[ tuple[ 0 ] + "With" ] = list.fireWith;});// Make the deferred a promisepromise.promise( deferred );// Call given func if anyif ( func ) {func.call( deferred, deferred );}// All done!return deferred;},// Deferred helper 执行一个或多个对象的延迟对象的回调函数when: function( subordinate /* , ..., subordinateN */ ) {return subordinate.promise();}
})

回调对象设计callbacks、异步回调解决方法deferred相关推荐

  1. layui表单提交使用form.on(‘submit(sub)‘,function (){}) 使用ajax请求时回调不执行的原因及解决方法

    layui表单提交使用form.on('submit(sub)',function (){}) 使用ajax请求时回调不执行的原因及解决方法 参考文章: (1)layui表单提交使用form.on(' ...

  2. golang github.com/go-sql-driver/mysql 遇到的数据库,设置库设计不合理的解决方法

    golang github.com/go-sql-driver/mysql 遇到的数据库,设置库设计不合理的解决方法,查询中报了以下这个错 Scan error on column index 2: ...

  3. vba mysql 80004005_Access运行时错误'-2147467259(80004005)':方法'Controls'作用于对象'CommandBarPopup'时失败的解决方法...

    时 间:2014-10-09 09:23:11 作 者: 摘 要:Access运行时错误'-2147467259(80004005)':方法'Controls'作用于对象'CommandBarPopu ...

  4. php paypal ipn回调,Paypal IPN / Webhook 异步回调流程是怎样的?

    里面提到的内容跟我遇到的差不多,我使用的是 Omnipay Paypal 包. 我之前直以为只要用户在 paypal 端完成支付,无论是否跳转回网站执行同步回调,IPN / Webhook 异步回调都 ...

  5. 微信支付异步回调mysql_微信支付异步回调,带你解决微信支付的深坑

    1.首先我们先下载微信支付的服务器端demo 2.个文件作用介绍 index.jsp  下单  payRequest.jsp  获取微信支付prepay_id等. 重点我说说这个payNotifyUr ...

  6. Request 对象 错误 'ASP 0104 : 80004005' 解决方法

    在windows server 2003下携带多个附件或者较大的附件进行发送时系统报错: Request 对象 错误 'ASP 0104 : 80004005' 不允许操作 /inc/config.a ...

  7. vue watch 监听不到变化_关于vue中watch检测到不到对象属性的变化的解决方法

    前言 在vue开发的过程中发现一个问题:改变vue.$data中对象的属性,watch是观测不到变化,但其实对象的属性是有变化的.这--,有点难以置信! 正文 update age with 25 e ...

  8. 手机WebAPP设计注意事项和解决方法

    1. 基本手机网页设计 1.1 wap端的网站表头 wap端的网站,写的时候首先注意表头,因为是手机端的,所以和我们平常用的web端页面的不一样,表头为: 1.2 尽量少使用水平滚动. 水平滚动除了比 ...

  9. 手机网页设计注意事项和解决方法

    原文: http://hi.baidu.com/onionsmm/item/977b8142e64b9b12886d10ea 一.关于手机页面的标准头 字符编码使用utf-8 指定页面手机内存缓存中的 ...

最新文章

  1. [Math]理解卡尔曼滤波器 (Understanding Kalman Filter)
  2. 进阶学习(4.4) JVM GC Root 判定, 垃圾的判定
  3. Java 7在整数中出现的次数
  4. WeakMap 本身释放,而 keyObject 没有释放的情况下,value 会释放吗?
  5. centos 日志审计_Linux\CentOS中auditd安全审计工具的使用
  6. python在工厂中的应用_Python工厂方法
  7. php算法求出兔子数列,PHP算法:斐波那契数列的N种算法
  8. SpringBoot 2.0 集成 JavaMail ,实现异步发送邮件
  9. zigbee学习之JN5169系统控制器
  10. [android开源]简单富文本编辑器MRichEditor,图文混排算个啥
  11. LCD直流数显多功能电压电流功率表电压电流表电量量产资料
  12. 教你用Python自制拼图小游戏,一起来玩吧
  13. java unbox_Java ValueConversions.unbox方法代码示例
  14. AST反混淆实战-经典ob混淆
  15. 为什么聪明人未能拯救世界?|《流浪地球》冷思考...
  16. 李开复演讲----给未来的你
  17. 基于java的springboot电影院订票售票系统毕业设计springboot开题报告
  18. 2018 计蒜之道 初赛 第三场
  19. 眼科考研院校排名及考研难度分析
  20. 【笨嘴拙舌WINDOWS】键盘消息,鼠标消息

热门文章

  1. Messagebox.Show()常用参数的讨论
  2. if ((MessageBox.Show(確定要關閉嗎﹖此次輸入數據將會丟失﹗, 確認, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) ==
  3. lighthouse_如何为CI / CD设置自动Lighthouse测试
  4. [浅析]UE4基本媒体交互控制
  5. c:out value= escapeXml=标签中的escapeXml的含义
  6. DELL服务器IDRAC固件(firmware)升级的解决方案
  7. python实现cc攻击_第二章 Requests库的使用:变相的cc攻击
  8. ant自动化打包新浪jar崩溃问题及解决方法
  9. uniapp离线打包升级SDK(iOS端)
  10. Why does uitableview cell remain highlighted?