日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

jquery源码之低调的回调函数队列--Callbacks

發(fā)布時(shí)間:2023/12/19 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jquery源码之低调的回调函数队列--Callbacks 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

jQuery中有一個(gè)很實(shí)用的函數(shù)隊(duì)列,可能我們很少用到,但他在jQuery內(nèi)部卻有著舉足輕重的地位。

他就是Callbacks. jQuery作者用它構(gòu)建了很多非常重要的模塊。比如說(shuō)$.Deferred。

Callbacks 說(shuō)白了就是個(gè)數(shù)組,里面存了很多函數(shù)對(duì)象。然而他真的 just so so么?

好吧,愛(ài)因斯坦也只是個(gè)人,但他真的僅僅是個(gè)普普通通的人嗎?Callbacks也不是。

不說(shuō)廢話了,先看源碼。

?

// String to Object options format cache var optionsCache = {};// Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) {var object = optionsCache[ options ] = {};jQuery.each( options.split( core_rspace ), function( _, flag ) {object[ flag ] = true;});return object; }/** Create a callback list using the following parameters:** options: an optional list of space-separated options that will change how* the callback list behaves or a more traditional option object** By default a callback list will act like an event callback list and can be* "fired" multiple times.** Possible options:** once: will ensure the callback list can only be fired once (like a Deferred)** memory: will keep track of previous values and will call any callback added* after the list has been fired right away with the latest "memorized"* values (like a Deferred)** unique: will ensure a callback can only be added once (no duplicate in the list)** stopOnFalse: interrupt callings when a callback returns false**/ jQuery.Callbacks = function( options ) {// Convert options from String-formatted to Object-formatted if needed// (we check in cache first)options = typeof options === "string" ?( optionsCache[ options ] || createOptions( options ) ) :jQuery.extend( {}, options );var // Last fire value (for non-forgettable lists)memory,// Flag to know if list was already firedfired,// Flag to know if list is currently firingfiring,// First callback to fire (used internally by add and fireWith)firingStart,// End of the loop when firingfiringLength,// Index of currently firing callback (modified by remove if needed)firingIndex,// Actual callback listlist = [],// Stack of fire calls for repeatable listsstack = !options.once && [],// Fire callbacksfire = function( data ) {memory = options.memory && data;fired = true;firingIndex = firingStart || 0;firingStart = 0;firingLength = list.length;firing = true;for ( ; list && firingIndex < firingLength; firingIndex++ ) {if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {memory = false; // To prevent further calls using addbreak;}}firing = false;if ( list ) {if ( stack ) {if ( stack.length ) {fire( stack.shift() );}} else if ( memory ) {list = [];} else {self.disable();}}},// Actual Callbacks objectself = {// Add a callback or a collection of callbacks to the listadd: function() {if ( list ) {// First, we save the current lengthvar start = list.length;(function add( args ) {jQuery.each( args, function( _, arg ) {var type = jQuery.type( arg );if ( type === "function" ) {if ( !options.unique || !self.has( arg ) ) {list.push( arg );}} else if ( arg && arg.length && type !== "string" ) {// Inspect recursivelyadd( arg );}});})( arguments );// Do we need to add the callbacks to the// current firing batch?if ( firing ) {firingLength = list.length;// With memory, if we're not firing then// we should call right away} else if ( memory ) {firingStart = start;fire( memory );}}return this;},// Remove a callback from the listremove: function() {if ( list ) {jQuery.each( arguments, function( _, arg ) {var index;while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {list.splice( index, 1 );// Handle firing indexesif ( firing ) {if ( index <= firingLength ) {firingLength--;}if ( index <= firingIndex ) {firingIndex--;}}}});}return this;},// Control if a given callback is in the listhas: function( fn ) {return jQuery.inArray( fn, list ) > -1;},// Remove all callbacks from the listempty: function() {list = [];return this;},// Have the list do nothing anymoredisable: function() {list = stack = memory = undefined;return this;},// Is it disabled?disabled: function() {return !list;},// Lock the list in its current statelock: function() {stack = undefined;if ( !memory ) {self.disable();}return this;},// Is it locked?locked: function() {return !stack;},// Call all callbacks with the given context and argumentsfireWith: function( context, args ) {args = args || [];args = [ context, args.slice ? args.slice() : args ];if ( list && ( !fired || stack ) ) {if ( firing ) {stack.push( args );} else {fire( args );}}return this;},// Call all the callbacks with the given argumentsfire: function() {self.fireWith( this, arguments );return this;},// To know if the callbacks have already been called at least oncefired: function() {return !!fired;}};return self; };

?

?代碼只有僅僅200行不到,但真正看起來(lái)卻又點(diǎn)繞,

《think in java》中有這么一句,理解一個(gè)程序最好的方法,就是把它看做一個(gè)服務(wù)的提供者。

那他提供了那些服務(wù):

首先我們看看返回的self對(duì)象

{// 添加方法add: function() {},// 刪除remove: function() {},// 是否包含has: function() {},// 清空empty: function() {},// 禁用disable: function() {},// 加鎖lock: function() {},// 是否加鎖locked: function() {},// 觸發(fā)fireWith: function(){},fire: function() {},// 是否觸發(fā)fired: function() {} }

  用途都十分清晰,那我們?cè)倏纯磪?shù),程序是服務(wù)的提供者,那么參數(shù)作為程序的入口的攜帶者,一般會(huì)用來(lái)裝配一些屬性。

顯然這里就是這樣。

?先看Callbacks內(nèi)部關(guān)于參數(shù)部分的代碼。

// 官方注釋,將配置的options由string格式轉(zhuǎn)換為object格式如果需要的話// Convert options from String-formatted to Object-formatted if needed// (we check in cache first)options = typeof options === "string" ?// 注意這里, 這里去取optionsCache的值,或者調(diào)用( optionsCache[ options ] || createOptions( options ) ) :jQuery.extend( {}, options );

  在看看createOptions方法吧,其實(shí)就是個(gè)轉(zhuǎn)換方法,還帶有緩存功能。

// String to Object options format cache // 建立一個(gè)緩存對(duì)象 var optionsCache = {};// Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) {// 創(chuàng)建optionsCache中的options屬性var object = optionsCache[ options ] = {};// 這里用到 each方法遍歷// options.split( core_rspace ) 根據(jù)空格劃分為數(shù)組// _在jquery中通常用來(lái)作為占位符,即忽略的參數(shù)jQuery.each( options.split( core_rspace ), function( _, flag ) {// 遍歷以后將切割后的每個(gè)屬性設(shè)置為trueobject[ flag ] = true;});return object; } // 可能例子會(huì)更清晰, var obj = createOptions( "once memory"); /* obj; {once: true,memory: true } */

  接下來(lái)就是具體的實(shí)現(xiàn)了,jQuery的實(shí)現(xiàn)一直是十分巧妙的,當(dāng)然這可能僅僅是小菜我看來(lái)。

/** Create a callback list using the following parameters:** options: an optional list of space-separated options that will change how* the callback list behaves or a more traditional option object** By default a callback list will act like an event callback list and can be* "fired" multiple times.** Possible options:** once: will ensure the callback list can only be fired once (like a Deferred)** memory: will keep track of previous values and will call any callback added* after the list has been fired right away with the latest "memorized"* values (like a Deferred)** unique: will ensure a callback can only be added once (no duplicate in the list)** stopOnFalse: interrupt callings when a callback returns false**/// jQuery.Callbacks = function( options ) {// Convert options from String-formatted to Object-formatted if needed// (we check in cache first)options = typeof options === "string" ?// 注意這里, 這里去取optionsCache的值,或者調(diào)用createOptions// 我們看看createOptions函數(shù)( optionsCache[ options ] || createOptions( options ) ) :jQuery.extend( {}, options );var // Last fire value (for non-forgettable lists)// 以前觸發(fā)的值(為了記憶的list,記憶了上次調(diào)用時(shí)所傳遞的基本信息(即記憶了參數(shù)))memory,// 是否觸發(fā)// Flag to know if list was already firedfired,// 是否正在觸發(fā)// Flag to know if list is currently firingfiring,// 第一個(gè)被觸發(fā)的function// First callback to fire (used internally by add and fireWith)firingStart,// 觸發(fā)列表的長(zhǎng)度// End of the loop when firingfiringLength,// 當(dāng)前觸發(fā)的索引// Index of currently firing callback (modified by remove if needed)firingIndex,// 內(nèi)部存放function的數(shù)組// Actual callback listlist = [],// 用來(lái)存放重復(fù)調(diào)用的數(shù)組,(當(dāng)Callbacks被配置了 once屬性,則為false)// Stack of fire calls for repeatable listsstack = !options.once && [],// 內(nèi)部觸發(fā)函數(shù),這里看到j(luò)query隱藏信息的習(xí)慣了// 作為該模塊的核心方法// 它沒(méi)有暴露給外部,// 《代碼大全》 有提到信息隱藏的好處。// Fire callbacksfire = function( data ) {// 在設(shè)置memory的情況下為 傳遞過(guò)來(lái)的參數(shù)data, 否則為undefinedmemory = options.memory && data;// 進(jìn)入到這時(shí)標(biāo)記已觸發(fā)fired = true;// 當(dāng)前觸發(fā)索引設(shè)置為開(kāi)始,或者0firingIndex = firingStart || 0;firingStart = 0;firingLength = list.length;firing = true;// for循環(huán)觸發(fā)list中的函數(shù)for ( ; list && firingIndex < firingLength; firingIndex++ ) {// 如果stopOnFalse被設(shè)置,則檢查調(diào)用函數(shù)后是否返回false// 如果返回則終止觸發(fā),// 注意觸發(fā)參數(shù) 為一個(gè)多維數(shù)組// data = [// context,// [args]//] 這應(yīng)該是由外部封裝成固定格式,再傳遞過(guò)來(lái)的參數(shù)if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {memory = false; // To prevent further calls using addbreak;}}// 設(shè)置正在觸發(fā)為falsefiring = false;// 如果list是存在的,即改callbacks還沒(méi)有被禁用if ( list ) {// 如果 stack中有值,則遞歸調(diào)用// 其實(shí)這里是判斷是否設(shè)置了once屬性if ( stack ) {if ( stack.length ) {fire( stack.shift() );}} else if ( memory ) { // 如果設(shè)置記憶功能,則清空l(shuí)ist(注意,是記憶需要調(diào)用的基本信息,即相關(guān)參數(shù))list = [];} else {// 只能調(diào)用一次,且不能使用memory,// 則禁用self.disable();}}},// 再來(lái)看看需要暴露的對(duì)象// Actual Callbacks objectself = {// 添加方法// Add a callback or a collection of callbacks to the listadd: function() {// list其實(shí)是可以作為是否禁用的標(biāo)志的,// 如果list存在if ( list ) {// First, we save the current lengthvar start = list.length;// 真正的添加行為// 用到了自執(zhí)行// 但又不是匿名函數(shù),因?yàn)樗赡苄枰f歸(function add( args ) {jQuery.each( args, function( _, arg ) {var type = jQuery.type( arg );if ( type === "function" ) {// 如果設(shè)置了唯一,且當(dāng)前已包含該函數(shù),// 則不添加,反之則添加函數(shù)if ( !options.unique || !self.has( arg ) ) {list.push( arg );}} else if ( arg && arg.length && type !== "string" ) { // 遞歸調(diào)用// Inspect recursivelyadd( arg );}});})( arguments );// Do we need to add the callbacks to the// current firing batch?// 如果正在觸發(fā),則只需要更新firingLengthif ( firing ) {firingLength = list.length;// With memory, if we're not firing then// we should call right away// 如果memory,則在添加的時(shí)候直接觸發(fā)} else if ( memory ) {firingStart = start;fire( memory );}}return this;},// Remove a callback from the list// 刪除方法,遍歷刪除指定的方法,并維護(hù)好firingLength以及firingIndexremove: function() {if ( list ) {jQuery.each( arguments, function( _, arg ) {var index;while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {list.splice( index, 1 );// Handle firing indexesif ( firing ) {if ( index <= firingLength ) {firingLength--;}if ( index <= firingIndex ) {firingIndex--;}}}});}return this;},// Control if a given callback is in the list// 是否包含has: function( fn ) {return jQuery.inArray( fn, list ) > -1;},// Remove all callbacks from the listempty: function() {list = [];return this;},// Have the list do nothing anymoredisable: function() {list = stack = memory = undefined;return this;},// Is it disabled?disabled: function() {// 看,這里有用到list是否存在來(lái)判斷 是否被禁用return !list;},// Lock the list in its current state// 鎖住即不能再被觸發(fā)// 如果沒(méi)有設(shè)置memory則直接禁用lock: function() {stack = undefined;if ( !memory ) {self.disable();}return this;},// 是否加鎖// Is it locked?locked: function() {// 居然是判斷stack是否存在// 由此推斷 加鎖應(yīng)該是設(shè)置智能觸發(fā)一次return !stack;},// Call all callbacks with the given context and argumentsfireWith: function( context, args ) {args = args || [];// 看這封裝了arguments,用來(lái)內(nèi)部fire函數(shù)的調(diào)用args = [ context, args.slice ? args.slice() : args ];// 如果還沒(méi)被觸發(fā),或者允許觸發(fā)多次if ( list && ( !fired || stack ) ) {// 正在觸發(fā),則添加到stack// 在當(dāng)次觸發(fā)后,直接觸發(fā)if ( firing ) {stack.push( args );} else {// 直接觸發(fā)fire( args );}}return this;},// Call all the callbacks with the given arguments// 設(shè)置context為thisfire: function() {self.fireWith( this, arguments );return this;},// To know if the callbacks have already been called at least oncefired: function() {return !!fired;}};// 注意有一個(gè)細(xì)節(jié),self的所有方法都是返回的this// 這表明,它是支持鏈?zhǔn)讲僮鞯?/ jquery 很多地方用了這種優(yōu)雅的技術(shù)return self; };

  好吧,Callbacks就講到這里了,神奇而低調(diào)的函數(shù)隊(duì)列,在以后的源碼中你也會(huì)經(jīng)常看到他的身影,所以他能做什么并不用著急。

但還是舉些小例子用用看:

var c = $.Callbacks("once memory"); c.add(function(i) {alert(123 + '-' + i); }); c.add(function(i) {alert(234 + '-' + i); }); c.add(function(i) {alert(456 + '-' + i); }); c.fire('tianxia'); // alert('123-tianxi'); alert('234-tianxi'); alert('456-tianxi'); c.fire(); // 再次調(diào)用,啥都沒(méi)發(fā)生,因?yàn)樵O(shè)置了once // 什么都沒(méi)發(fā)生 c.add(function(i) {alert(i); }); // alert('tianxia') // 在設(shè)置memory,添加后,直接觸發(fā)

  

轉(zhuǎn)載于:https://www.cnblogs.com/w2154/p/4570599.html

總結(jié)

以上是生活随笔為你收集整理的jquery源码之低调的回调函数队列--Callbacks的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。