回调对象设计callbacks、异步回调解决方法deferred
callbacks使用方法
callbacks原理分析
deferred概念 及 使用方法
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作为一个模型,提供了一个在软件工程中描述掩饰(或将来)概念的解决方案。
- promise表示一个异步操作的最终结果。
- 与promise最主要的交互方法是,通过将函数传入它的then方法,从而获取得promise最终的值或promise最终拒绝(reject)的原因。
- 一个promise必须处于以下状态的其中之一: pending fulfilled或rejected
- 一个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相关推荐
- layui表单提交使用form.on(‘submit(sub)‘,function (){}) 使用ajax请求时回调不执行的原因及解决方法
layui表单提交使用form.on('submit(sub)',function (){}) 使用ajax请求时回调不执行的原因及解决方法 参考文章: (1)layui表单提交使用form.on(' ...
- golang github.com/go-sql-driver/mysql 遇到的数据库,设置库设计不合理的解决方法
golang github.com/go-sql-driver/mysql 遇到的数据库,设置库设计不合理的解决方法,查询中报了以下这个错 Scan error on column index 2: ...
- vba mysql 80004005_Access运行时错误'-2147467259(80004005)':方法'Controls'作用于对象'CommandBarPopup'时失败的解决方法...
时 间:2014-10-09 09:23:11 作 者: 摘 要:Access运行时错误'-2147467259(80004005)':方法'Controls'作用于对象'CommandBarPopu ...
- php paypal ipn回调,Paypal IPN / Webhook 异步回调流程是怎样的?
里面提到的内容跟我遇到的差不多,我使用的是 Omnipay Paypal 包. 我之前直以为只要用户在 paypal 端完成支付,无论是否跳转回网站执行同步回调,IPN / Webhook 异步回调都 ...
- 微信支付异步回调mysql_微信支付异步回调,带你解决微信支付的深坑
1.首先我们先下载微信支付的服务器端demo 2.个文件作用介绍 index.jsp 下单 payRequest.jsp 获取微信支付prepay_id等. 重点我说说这个payNotifyUr ...
- Request 对象 错误 'ASP 0104 : 80004005' 解决方法
在windows server 2003下携带多个附件或者较大的附件进行发送时系统报错: Request 对象 错误 'ASP 0104 : 80004005' 不允许操作 /inc/config.a ...
- vue watch 监听不到变化_关于vue中watch检测到不到对象属性的变化的解决方法
前言 在vue开发的过程中发现一个问题:改变vue.$data中对象的属性,watch是观测不到变化,但其实对象的属性是有变化的.这--,有点难以置信! 正文 update age with 25 e ...
- 手机WebAPP设计注意事项和解决方法
1. 基本手机网页设计 1.1 wap端的网站表头 wap端的网站,写的时候首先注意表头,因为是手机端的,所以和我们平常用的web端页面的不一样,表头为: 1.2 尽量少使用水平滚动. 水平滚动除了比 ...
- 手机网页设计注意事项和解决方法
原文: http://hi.baidu.com/onionsmm/item/977b8142e64b9b12886d10ea 一.关于手机页面的标准头 字符编码使用utf-8 指定页面手机内存缓存中的 ...
最新文章
- [Math]理解卡尔曼滤波器 (Understanding Kalman Filter)
- 进阶学习(4.4) JVM GC Root 判定, 垃圾的判定
- Java 7在整数中出现的次数
- WeakMap 本身释放,而 keyObject 没有释放的情况下,value 会释放吗?
- centos 日志审计_Linux\CentOS中auditd安全审计工具的使用
- python在工厂中的应用_Python工厂方法
- php算法求出兔子数列,PHP算法:斐波那契数列的N种算法
- SpringBoot 2.0 集成 JavaMail ,实现异步发送邮件
- zigbee学习之JN5169系统控制器
- [android开源]简单富文本编辑器MRichEditor,图文混排算个啥
- LCD直流数显多功能电压电流功率表电压电流表电量量产资料
- 教你用Python自制拼图小游戏,一起来玩吧
- java unbox_Java ValueConversions.unbox方法代码示例
- AST反混淆实战-经典ob混淆
- 为什么聪明人未能拯救世界?|《流浪地球》冷思考...
- 李开复演讲----给未来的你
- 基于java的springboot电影院订票售票系统毕业设计springboot开题报告
- 2018 计蒜之道 初赛 第三场
- 眼科考研院校排名及考研难度分析
- 【笨嘴拙舌WINDOWS】键盘消息,鼠标消息
热门文章
- Messagebox.Show()常用参数的讨论
- if ((MessageBox.Show(確定要關閉嗎﹖此次輸入數據將會丟失﹗, 確認, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) ==
- lighthouse_如何为CI / CD设置自动Lighthouse测试
- [浅析]UE4基本媒体交互控制
- c:out value= escapeXml=标签中的escapeXml的含义
- DELL服务器IDRAC固件(firmware)升级的解决方案
- python实现cc攻击_第二章 Requests库的使用:变相的cc攻击
- ant自动化打包新浪jar崩溃问题及解决方法
- uniapp离线打包升级SDK(iOS端)
- Why does uitableview cell remain highlighted?