自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

jQuery最核心基礎(chǔ)設(shè)施:數(shù)據(jù)緩存模塊進(jìn)化史

開(kāi)發(fā) 前端
數(shù)據(jù)緩存系統(tǒng)最早應(yīng)該是jQuery1.2引入的,那時(shí)它的事件系統(tǒng)完成照搬DE大神的addEvent.js,而addEvent在實(shí)現(xiàn)有個(gè)缺憾,它把事件的回調(diào)都放到EventTarget之上,這會(huì)引發(fā)循環(huán)引用,如果EventTarget是window對(duì)象,又會(huì)引發(fā)全局污染。有了數(shù)據(jù)緩存系統(tǒng),除了規(guī)避這兩個(gè)風(fēng)險(xiǎn)外,我們還可以有效地保存不同方法產(chǎn)生的中間變量,而這些變量會(huì)對(duì)另一個(gè)模塊的方法有用,解耦方法間的依賴。對(duì)于jQuery來(lái)說(shuō),它的事件克隆乃至后來(lái)的列隊(duì)實(shí)現(xiàn)都是離不開(kāi)緩存系統(tǒng)。

jQuery1.2 在core模塊新增了兩個(gè)靜態(tài)方法, data與removeData。data不用說(shuō),與jQuery其他方法一樣,讀寫結(jié)合。jQuery的緩存系統(tǒng)是把所有數(shù)據(jù)都放$.cache之上,然后為每個(gè)要使用緩存系統(tǒng)的元素節(jié)點(diǎn),文檔對(duì)象與window對(duì)象分配一個(gè)UUID。UUID的屬性名為一個(gè)隨機(jī)的自定義屬性,"jQuery" + (new Date()).getTime(), 值為整數(shù),從零遞增。但UUID總要附于一個(gè)對(duì)象上,如果那個(gè)對(duì)象是window,豈不是全局污染嗎,因此jQuery內(nèi)部判定它是window對(duì)象時(shí),映射為一個(gè)叫windowData的空對(duì)象,然后UUID加在它之上。有了UUID,我們?cè)谑状卧L問(wèn)緩存系統(tǒng)時(shí),會(huì)在$.cache對(duì)象開(kāi)辟一個(gè)空對(duì)象(緩存體),用于放置與目標(biāo)對(duì)象有關(guān)的東西。這有點(diǎn)像銀行開(kāi)戶了,UUID的值就是存折。removeData則會(huì)刪掉不再需要保存數(shù)據(jù),如果到最后,數(shù)據(jù)刪清光了,它也沒(méi)有任何鍵值對(duì),成為空對(duì)象,jQuery就會(huì)從$.cache中刪掉此對(duì)象,并從目標(biāo)對(duì)象移除UUID。

  1. //jQuery1.2.3 
  2. var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; 
  3. jQuery.extend({ 
  4.     cache: {}, 
  5.     data: function( elem, name, data ) { 
  6.         elem = elem == window ? windowData :   elem;//對(duì)window對(duì)象做特別處理 
  7.         var id = elem[ expando ]; 
  8.         if ( !id ) //如果沒(méi)有UUID則新設(shè)一個(gè) 
  9.             id = elem[ expando ] = ++uuid; 
  10.         //如果沒(méi)有在$.cache中開(kāi)戶,則先開(kāi)戶 
  11.         if ( name && !jQuery.cache[ id ] ) 
  12.             jQuery.cache[ id ] = {}; 
  13.   
  14.         // 第三個(gè)參數(shù)不為undefined時(shí),為寫操作 
  15.         if ( data != undefined ) 
  16.             jQuery.cache[ id ][ name ] = data; 
  17.         //如果只有一個(gè)參數(shù),則返回緩存對(duì)象,兩個(gè)參數(shù)則返回目標(biāo)數(shù)據(jù) 
  18.         return name ?  jQuery.cache[ id ][ name ] :   id; 
  19.     }, 
  20.   
  21.     removeData: function( elem, name ) { 
  22.         elem = elem == window ? windowData :   elem; 
  23.         var id = elem[ expando ]; 
  24.         if ( name ) {//移除目標(biāo)數(shù)據(jù) 
  25.             if ( jQuery.cache[ id ] ) { 
  26.                 delete jQuery.cache[ id ][ name ]; 
  27.                 name = ""
  28.   
  29.                 for ( name in jQuery.cache[ id ] ) 
  30.                     break
  31.                 //遍歷緩存體,如果不為空,那name會(huì)被改寫,如果沒(méi)有被改寫,則!name 為true, 
  32.                 //從而引發(fā)再次調(diào)用此方法,但這次是只傳一個(gè)參數(shù),移除緩存體, 
  33.                 if ( !name ) 
  34.                     jQuery.removeData( elem ); 
  35.             } 
  36.         } else { 
  37.             //移除UUID,但I(xiàn)E下對(duì)元素使用delete會(huì)拋錯(cuò) 
  38.             try { 
  39.                 delete elem[ expando ]; 
  40.             } catch(e){ 
  41.                 if ( elem.removeAttribute ) 
  42.                     elem.removeAttribute( expando ); 
  43.             }//注銷賬戶 
  44.             delete jQuery.cache[ id ]; 
  45.         } 
  46.     } 
  47. }) 

jQuery在1.2.3中添加了兩個(gè)同名的原型方法data與removeData,目的是方便鏈?zhǔn)讲僮髋c集化操作。并在data中添加getData, setData的自定義事件的觸發(fā)邏輯。

1.3中,數(shù)據(jù)緩存系統(tǒng)終于獨(dú)立成一個(gè)模塊data.js(內(nèi)部開(kāi)發(fā)時(shí)的劃分),并添加了兩組方法,命名空間上的queue與dequeue,原型上的queue與dequeue。queue的目的很明顯,就是緩存一組數(shù)據(jù),為動(dòng)畫模塊服務(wù)。dequeue是從一組數(shù)據(jù)中刪掉一個(gè)。

  1. //jQuery1.3 
  2. jQuery.extend({ 
  3.     queue: function( elem, type, data ) { 
  4.         if ( elem ){ 
  5.             type = (type || "fx") + "queue"
  6.             var q = jQuery.data( elem, type ); 
  7.             if ( !q || jQuery.isArray(data) )//確保儲(chǔ)存的是一個(gè)數(shù)組 
  8.                 q = jQuery.data( elem, type, jQuery.makeArray(data) ); 
  9.             else if( data )//然后往這個(gè)數(shù)據(jù)加?xùn)|西 
  10.                 q.push( data ); 
  11.         } 
  12.         return q; 
  13.     }, 
  14.     dequeue: function( elem, type ){ 
  15.         var queue = jQuery.queue( elem, type ), 
  16.         fn = queue.shift();//然后刪掉一個(gè),早期它是放置動(dòng)畫的回調(diào),刪掉它就call一下, 
  17.         // 但沒(méi)有做是否為函數(shù)的判定,估計(jì)也沒(méi)有寫到文檔中,為內(nèi)部使用 
  18.         if( !type || type === "fx" ) 
  19.             fn = queue[0]; 
  20.         if( fn !== undefined ) 
  21.             fn.call(elem); 
  22.     } 
  23. }) 

fx模塊animate方法的調(diào)用示例:

  1. //each是并行處理多個(gè)動(dòng)畫,queue是一個(gè)接一個(gè)處理多個(gè)動(dòng)畫 
  2. this[ optall.queue === false ? "each" : "queue" ](function(){ /*略*/}) 

在元素上添加自定義屬性,還會(huì)引發(fā)一個(gè)問(wèn)題。如果我們對(duì)這個(gè)元素進(jìn)行拷貝,就會(huì)將此屬性也會(huì)復(fù)制過(guò)去,導(dǎo)致兩個(gè)元素都有相同的UUID值,出現(xiàn)數(shù)據(jù)被錯(cuò)誤操作的情況。jQuery早期的復(fù)制節(jié)點(diǎn)實(shí)現(xiàn)非常簡(jiǎn)單,如果元素的cloneNode方法不會(huì)復(fù)制事件就使用cloneNode,否則使用元素的outerHTML,或父節(jié)點(diǎn)的innerHTML,用clean方法解析一個(gè)新元素出來(lái)。但outerHTML與innerHTML都會(huì)顯式屬性寫在里面,因此需要用正則把它們清除掉。

  1. //jQuery1.3.2 core.js clone方法 
  2. var ret = this.map(function(){ 
  3.     if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) { 
  4.         var html = this.outerHTML; 
  5.         if ( !html ) { 
  6.             var div = this.ownerDocument.createElement("div"); 
  7.             div.appendChild( this.cloneNode(true) ); 
  8.             html = div.innerHTML; 
  9.         } 
  10.   
  11.         return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0]; 
  12.     } else 
  13.         return this.cloneNode(true); 
  14. }); 

jQuery1.4發(fā)現(xiàn)IE如果對(duì)于object, ember, applet這三個(gè)古老的用于接入外部資源的標(biāo)簽可能會(huì)拋錯(cuò)。由于舊式IE的元素節(jié)點(diǎn)只是COM的包裝,一旦引入資源后,它就會(huì)變成那種資源的實(shí)例,而它們會(huì)有嚴(yán)格的訪問(wèn)控制,不能像普通的JS對(duì)象那樣隨意添加成員。于是jQuery便一刀換,但凡是這三種標(biāo)簽,就不為它緩存數(shù)據(jù)。jQuery弄了一個(gè)叫noData的hash,用于檢測(cè)元素節(jié)點(diǎn)的標(biāo)簽。

  1. noData: { 
  2.     "embed"true
  3.     "object"true
  4.     "applet"true 
  5. }, 
  6. //代碼防御        
  7. if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { 
  8.     return

jQuery1.4還對(duì)$.data進(jìn)行改進(jìn),允許第二個(gè)參數(shù)為對(duì)象,方便儲(chǔ)存多個(gè)數(shù)據(jù)。UUID對(duì)應(yīng)的自定義屬性expando 也放進(jìn)命名空間之下了。queue與dequeue方法被剝離成一個(gè)新模塊。

jQuery1.43帶來(lái)三項(xiàng)改進(jìn)。

首先是添加changeData自定義方法。不過(guò)這套方法沒(méi)有什么銷量,只是產(chǎn)品經(jīng)理的自戀吧。

檢測(cè)元素節(jié)點(diǎn)是否支持添加自定義屬性的邏輯被獨(dú)立成一個(gè)叫acceptData的方法。因?yàn)閖Query團(tuán)隊(duì)發(fā)現(xiàn)當(dāng)object標(biāo)簽加載的flash資源,它還是可以添加自定義屬性的,于是決定對(duì)這種情況網(wǎng)開(kāi)一面。IE在加載flash時(shí),需要對(duì)object指定一個(gè)叫classId的屬性,值為clsid:D27CDB6E-AE6D-11cf-96B8-444553540000,因此檢測(cè)邏輯就變得非常復(fù)雜,由于data, removeData都要用到,獨(dú)立出來(lái)有效節(jié)省比特。

HTML5對(duì)人們隨便添加自定義屬性的行為做出回應(yīng),新增一種叫"data-*"的緩存機(jī)制。當(dāng)用戶設(shè)置的屬性以"data-"開(kāi)頭,它們會(huì)被保存到元素節(jié)點(diǎn)的dataset對(duì)象上。這就導(dǎo)致人們可能用HTML5方便緩存數(shù)據(jù),也可能用jQuery的緩存系統(tǒng)保存數(shù)據(jù),那么data方法就變得有點(diǎn)不中用了。于是jQuery在原型上的data做了增強(qiáng),當(dāng)用戶第一次訪問(wèn)此元素節(jié)點(diǎn),會(huì)遍歷它所有"data-"開(kāi)頭的自定義屬性(為了照顧舊式IE,不能直接遍歷dataset),把它們放到j(luò)Query的緩存體中。那么當(dāng)用戶取數(shù)據(jù)時(shí),會(huì)先從緩存系統(tǒng)中,沒(méi)有再使用setAttribute訪問(wèn)"data-"自定義屬性。但HTML5的緩存系統(tǒng)非常弱,只能保存字符串(這當(dāng)然是出于循環(huán)引用的考量),于是jQuery會(huì)將它們還原為各種數(shù)據(jù)類型,如"null",, "false", "true"變成null, false, true, 符合數(shù)字格式的字符串會(huì)轉(zhuǎn)換成數(shù)字,如果它是以"{"開(kāi)頭"}"結(jié)尾則嘗試轉(zhuǎn)成一個(gè)對(duì)象。

 

  1. //jQuery1.43 $.fn.data 
  2. rbrace = /^(?:\{.*\}|\[.*\])$/; 
  3. if ( data === undefined && this.length ) { 
  4.     data = jQuery.data( this[0], key ); 
  5.     if ( data === undefined && this[0].nodeType === 1 ) { 
  6.         data = this[0].getAttribute( "data-" + key ); 
  7.   
  8.         if ( typeof data === "string" ) { 
  9.             try { 
  10.                 data = data === "true" ? true : 
  11.                     data === "false" ? false : 
  12.                     data === "null" ? null : 
  13.                     !jQuery.isNaN( data ) ? parseFloat( data ) : 
  14.                     rbrace.test( data ) ? jQuery.parseJSON( data ) : 
  15.                     data; 
  16.             } catch( e ) {} 
  17.   
  18.         } else { 
  19.             data = undefined; 
  20.         } 
  21.     } 

jQuery1.5也帶來(lái)三項(xiàng)改進(jìn)。當(dāng)時(shí)jQuery已經(jīng)在1.42打敗Prototype.js,如日中天,馬太效應(yīng),用戶量暴增。它的重點(diǎn)改為提升性能,進(jìn)入fix bug階段(用戶多,相當(dāng)于免費(fèi)的測(cè)試員就越多,測(cè)試覆蓋面就越大)。

改進(jìn)expando,原來(lái)是基于時(shí)間截,現(xiàn)在是版本號(hào)加隨機(jī)數(shù)。因此用戶可能在一個(gè)頁(yè)面引入多個(gè)版本的jQuery。

是否有此數(shù)據(jù)的邏輯被抽出成一個(gè)hasData方法,處理HTML5的"data-*"屬性也被抽出成一個(gè)私有方法dataAttr。它們都是為了邏輯顯得更清晰。dataAttr使用JSON.parse,由于這個(gè)JSON可能是JSON2.js引入的,而JSON2.js有個(gè)非常糟糕的地方,就是為一系列原生類型添加了toJSON方法,導(dǎo)致for in 循環(huán)判定是否為空對(duì)象出錯(cuò)。jQuery被逼搞了個(gè)isEmptyDataObject方法做處理。

jQuery的數(shù)據(jù)緩存系統(tǒng)本來(lái)就是為事件系統(tǒng)服務(wù)而分化出來(lái)的,到后來(lái),它是內(nèi)部眾多模塊的基礎(chǔ)設(shè)施。換言之,它內(nèi)部會(huì)儲(chǔ)存許多框架用戶的變量(系統(tǒng)數(shù)據(jù)),但一旦它公開(kāi)到文檔中,用戶也會(huì)使用data保存他們務(wù)業(yè)中使用的數(shù)據(jù)(用戶數(shù)據(jù))。以前,用戶小,變量名沖突的可能性比較少,加之jQuery為這些系統(tǒng)數(shù)據(jù)精挑了一些不常用的名字,__class__, __change__或加個(gè)后綴什么的,沒(méi)有收到什么投訴。當(dāng)jQuery成為世界級(jí)的著名框架后,用戶數(shù)據(jù)名干掉系統(tǒng)數(shù)據(jù)名,導(dǎo)致事件系統(tǒng)或其他什么模塊癱瘓就時(shí)有發(fā)生。jQuery開(kāi)始對(duì)緩存體進(jìn)行改造,原來(lái)就是一個(gè)對(duì)象,什么數(shù)據(jù)都往里面拋。現(xiàn)在它就這個(gè)緩存體內(nèi)開(kāi)辟一個(gè)子對(duì)象,鍵名為隨機(jī)的jQuery.expando值,如果是系統(tǒng)數(shù)據(jù)就存到里面去。但events系統(tǒng)數(shù)據(jù)為了向前兼容起見(jiàn),還是直接放到緩存體之上。至于,如何區(qū)分是系統(tǒng)數(shù)據(jù),非常簡(jiǎn)單,直接在data方法添加第四個(gè)參數(shù),真值時(shí)為系統(tǒng)數(shù)據(jù)。removeData時(shí)也相應(yīng)提供第三個(gè)參數(shù),用于刪除系統(tǒng)數(shù)據(jù)。還新設(shè)了一個(gè)_data方法,專門用于操作系統(tǒng)數(shù)據(jù)。下面就是緩存體的結(jié)構(gòu)圖:

  1.  var cache = { 
  2.      jQuery14312343254:{/*放置系統(tǒng)數(shù)據(jù)*/
  3.      events: {/"放置事件名與它對(duì)應(yīng)的回調(diào)列表"/} 
  4.      /*這里放置用戶數(shù)據(jù)*/ 
  5. jQuery1.7對(duì)緩存體做了改進(jìn),系統(tǒng)變量變放置data對(duì)象中,為此判定緩存體為空也要做相應(yīng)的改進(jìn),現(xiàn)在要跳過(guò)toJSON與data。新結(jié)構(gòu)如下: 
  6.  
  7. var cache = { 
  8.      data:{/*放置用戶數(shù)據(jù)*/
  9.      /*這里放置系統(tǒng)數(shù)據(jù)*/ 

jQuery1.8曾添加一個(gè)叫deleteIds的數(shù)組,用于重用UUID,但曇花一現(xiàn)。UUID的值從1.8起不用jQuery.uuid的了,改用jQuery.guid遞增生成。重大的改進(jìn)在jQuery1.83后,操作數(shù)據(jù)的實(shí)現(xiàn)被抽出為私有方法,命名空間與原型上的方法只是一個(gè)代理,并分成兩組方法,操作用戶數(shù)據(jù)的data, removeData,操作系統(tǒng)數(shù)據(jù)的_data,_removeData?,F(xiàn)在光是緩存系統(tǒng)就是一個(gè)龐大家族了。

說(shuō)到底,數(shù)據(jù)緩存就是在目標(biāo)對(duì)象與緩存體間建立一對(duì)一的關(guān)系,然后在緩存體上操作數(shù)據(jù),復(fù)雜度都集在前者。而在一個(gè)普通JS對(duì)象進(jìn)行增刪改查某屬性從來(lái)沒(méi)有難度,用戶怎么也玩不出花招。從軟件設(shè)計(jì)原則上看,這也是最好的結(jié)果(吻合KISS原則與職責(zé)單一則)。

原文鏈接:http://www.cnblogs.com/rubylouvre/archive/2012/11/19/2776286.html

【編輯推薦】

責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2019-06-19 15:54:12

Redis緩存內(nèi)存

2011-12-21 16:44:00

信息圖手機(jī)進(jìn)化史

2018-08-23 09:33:12

2024-09-21 10:43:15

數(shù)據(jù)技術(shù)信息

2018-03-23 12:20:25

數(shù)據(jù)中心網(wǎng)絡(luò)數(shù)據(jù)

2014-09-01 16:29:34

2010-07-27 14:04:52

2011-11-03 15:25:07

Android

2011-09-01 09:34:21

架構(gòu)

2011-11-29 09:54:20

Google進(jìn)化史

2018-08-22 17:58:01

數(shù)據(jù)平臺(tái)數(shù)據(jù)倉(cāng)庫(kù)架構(gòu)

2023-05-12 15:15:23

數(shù)字化轉(zhuǎn)型大數(shù)據(jù)

2010-04-07 14:54:20

Unix操作系統(tǒng)

2010-01-21 16:08:26

C++語(yǔ)言

2010-10-09 14:46:20

2018-12-21 11:01:05

存儲(chǔ)大數(shù)據(jù)RAID

2014-08-13 10:31:26

Windows操作系統(tǒng)

2013-06-24 09:18:05

2011-11-04 15:58:52

手機(jī)操作系統(tǒng)進(jìn)化史

2019-08-29 08:13:28

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)