内容简介:jQuery封装了很多关于异步操作的方法,比如$.Callbacks()返回一个Callbacks对象,你可以调用该对象的方法对函数列表进行操作,要实现这样的功能很简单,下面是一个简易的实现同样的功能,只不过jQuery支持了不同的调用方式
jQuery封装了很多关于异步操作的方法,比如 $.ajax
$.Deferred
等等,这些方法都是以Callbacks为基础开发的,Callbacks一个多用途的回调列表对象,提供了强大的的方式来管理回调函数列表,他可以管理一个列表,在你需要执行时候触发,触发时机由调用fire方法决定
了解API
var cb = $.Callbacks(); cb.add(function(){ console.log('first function'); }) cb.add(function () { console.log('second function'); }) cb.fire(); // first function // second function 复制代码
$.Callbacks()返回一个Callbacks对象,你可以调用该对象的方法对函数列表进行操作,要实现这样的功能很简单,下面是一个简易的实现
function Callbakcs () { var list = [] return { add: function (func) { list.push(func); }, fire: function () { var args = [].slice.call(arguments); list.forEach(function(item) { item.apply(null, arguments); }) } } } 复制代码
同样的功能,只不过jQuery支持了不同的调用方式
参数
在调用$.Callbacks的时候,我们可以传入一个参数用来改变回调列表的行为
- once 确保改列表只执行一次,调用fire过后便失效
- unique 一个回调只会被添加一次,不会重复添加
- stopOnFalse 在某一个回调返回false时候立即停止执行后面函数
- memory 缓存上一次fire的参数,下一次add的时候执行用上一次的参数调用
// 支持两种传参方式,一种对象类的,一种字符串类的,可组合使用,传入字符串的时候会对字符串进行处理转换为对象 var cb = $.Callback("once unique"); var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); function createOptions( options ) { var object = {}; jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { object[ flag ] = true; } ); return object; } // 函数内部存储了一个options对象,最后会是类似{once: true, unique: true}这样的对象 复制代码
变量说明
在函数内部我们还能看到其他一些变量
var // 标记是否正在触发 firing, // 缓存的上一次调用时候的参数和this指向 memory, // 标记是否已经调用过fire fired, // 防止调用的标记 locked, // 回调列表 list = [], // 参数和this指向的列表 queue = [], // 标记当前执行到哪个回调 firingIndex = -1, // 执行回调列表 fire = function () {} // 暴露的对象 self = {} 复制代码
add
add方法主要会判断是否是unique、memory模式、unique遇到相同的回调函数回过滤掉,memory会检查fired是否为true,如果是会将memory里面的参数添加到queue队列中,最后调用fire
if ( memory && !firing ) { firingIndex = list.length - 1; queue.push( memory ); } if ( memory && !firing ) { firingIndex = list.length - 1; queue.push( memory ); } ( function add( args ) { jQuery.each( args, function( _, arg ) { if ( isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } } else if ( arg && arg.length && toType( arg ) !== "string" ) { // Inspect recursively add( arg ); } } ); } )( arguments ); 复制代码
添加的是否用到了递归,因为支持了传入数组的方法
fire
self里面会调用fireWith方法,我们在调用fire的时候实际上是调用的这个方法
fire: function() { self.fireWith( this, arguments ); return this; }, fireWith: function( context, args ) { if ( !locked ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; // 降参数和this对象缓存到queue里面 queue.push( args ); if ( !firing ) { fire(); } } return this; }, 复制代码
真正的fire会遍历取出queue里面的参数,缓存到memory里面,如果不是memory模式则会在后面清除掉,遍历list,用memory里的参数调用各个方法
for ( ; queue.length; firingIndex = -1 ) { memory = queue.shift(); while ( ++firingIndex < list.length ) { // 如果传入stopOnFalse,且返回false,立即停止遍历 if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && options.stopOnFalse ) { firingIndex = list.length; memory = false; } } } 复制代码
Callback部分的代码比较简单,当然这部分都是同步逻辑,callback是Deffered的基础,所以需要先明白一下原理
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- JStorm 源码分析 - 异步循环线程 AsyncLoopThread
- YYText 源码剖析:CoreText 与异步绘制
- React Fiber源码分析 第三篇(异步状态)
- 原 荐 Java异步编程——深入源码分析FutureTask
- corefx 源码学习:NetworkStream.ReadAsync 是如何从 Socket 异步读取数据的
- SpringBoot | :异步开发之异步调用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。