jQuery 1.5最新版本的改進細節(jié)分析
更新時間:2011年01月19日 23:39:15 作者:
jQuery 1.5 beta1出來了,從學習跟進上來說,這一次已經(jīng)比較晚了(我竟然不知道1.5什么時候出的alpha,就這么beta了)。
這個1.5版本最大的更新是AJAX的完全重寫,提供了更強的可擴展性。但是受制于精力和篇幅,對新的AJAX的分析還是放到下回,本篇先簡單介紹一下細節(jié)方面的改進。
jQuery._Deferred和jQuery.Deferred
首先不得不說這兩個新生事物,因為他們是作為基礎設施存在,不把這兩個東西講明白了,有些問題根本沒辦法解釋。
首先,jQuery.Deferred是jQuery._Deferred的增強版,因此對于這個問題,從jQuery._Deferred入手,就能說明一大半的問題。
什么是Deferred?從字面上看,我的第一反應是“延遲加載”,首字母大寫的應該是“類型”的定義,所以這大概是一個“透明提供延遲加載功能”的類型吧。然而實際上,雖然確實帶有那么一點點“延遲”的意思,這個東西卻不是用來實現(xiàn)延遲加載的。
簡單來說,jQuery._Deferred是一個函數(shù)隊列,他的作用有以下幾點:
保存若干個函數(shù)。
在特定的時刻把保存著的函數(shù)全部執(zhí)行掉。
執(zhí)行過后,新進來的函數(shù)會立刻執(zhí)行。
感覺是不是和啥東西很像?對,jQuery的ready函數(shù)就是這樣的邏輯,實際中jQuery 1.5中的ready函數(shù)也確實被嫁接到這上面去了。
jQuery._Deferred提供下面的接口:
done:function(fn1, fn2, ...)的形式,用于把函數(shù)添加到隊列中。
fire:function(context, args)的形式,使用context指定this對象,args指定參數(shù),調(diào)用隊列中所有函數(shù)。fire被調(diào)用后,_Deferred會進入isResolved狀態(tài),未來對done的調(diào)用不會再保存函數(shù),而是直接調(diào)用函數(shù)。
resolve:相當于調(diào)用fire(this, arguments),一個簡化的方法。
isResolved:用來判斷_Deferred是否在isResolved狀態(tài),具體參考前面的fire函數(shù)的解釋。
cancel:取消掉整個隊列,這樣不管未來是不是fire,隊列中的函數(shù)都不會再被調(diào)用。
說明白了jQuery._Deferred,再來看看jQuery.Deferred。這個東西其實就是2個_Deferred組成的,第一個稱為deferred,用于保管“正常”狀態(tài)下的函數(shù);第二個稱為failDeferred,用于保管“出錯”狀態(tài)下的函數(shù)。同時jQuery.Deferred提供了一些新的接口:
then:function(done, fail)的形式,把done添加進deferred,把fail添加進failedDeferred。
fail:相當于failDeferred的done函數(shù)。
fireReject:相當于failDeferred的fire函數(shù)。
reject:相當于failDeferred的resolve函數(shù)。
isRejected:相當于failDeferred的isResolved函數(shù)。
同時jQuery.Deferred取消了cancel函數(shù)。
那么這個是啥用的呢?有“正?!焙汀俺鲥e”2個狀態(tài),同時又是異步的,很容易就能想到……對,給AJAX用的,在下一篇分析中再詳細說明。
jQuery.ready的變化
因為有了jQuery._Deferred這個東西,jQuery.ready函數(shù)變成依賴于函數(shù)隊列,具體的變化有:
原來的readyList變量已經(jīng)不再是一個數(shù)組,而變成了jQuery._Deferred對象。
原本在DOMContentLoaded時,調(diào)用readList中所有函數(shù)的邏輯,現(xiàn)在也使用了jQuery._Deferred中,原來的代碼:
while ( (fn = ready[ i++ ]) ) {
fn.call( document, jQuery );
}
變成了:
readyList.fire( document , [ jQuery ] );
jQuery.parseXML函數(shù)
新增了靜態(tài)函數(shù)jQuery.parseXML,用于提供瀏覽器兼容的從字符串轉(zhuǎn)為XML文檔的功能。
該函數(shù)的邏輯網(wǎng)上有很多,jQuery也沒有特別的地方,大致分為以下2種:
對于標準瀏覽器,使用DOMParser對象:
var parser = new DOMParser();
var xml = parser.parseFromString(text, 'text/html');對于IE,使用Microsoft.XMLDOM對象:
var parser = new ActiveXObject('Microsoft.XMLDOM');
parser.async = 'false';
parser.loadXML(text);
var xml = parser.documentElement;
data部分
添加了jQuery.hasData函數(shù),用于判斷一個元素是否有jQuery附加上去的數(shù)據(jù)。
修改了jQuery.expando的實現(xiàn),在原來單純地取當前時間的基礎上,添加了一個隨機數(shù):
expando = "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" );這樣保證在同一時間,引入多個jQuery副本,這幾個副本之間的expando不會相互沖突,導致元素上的data變得錯亂。一般來說,是不會引入多個jQuery副本的,但是使用SealJS等的時候,配置不當?shù)脑?,也是很容易出現(xiàn)此類問題的。
DOM操作部分
原本的hasClass、addClass、removeClass函數(shù)都需要將元素的class屬性分隔為數(shù)組,在1.4.4版本中,通過\n或\t進行分隔,在1.5中增加了一個\r,用于對應Windows平臺下的換行符(\r\n)。
jQuery.fn.attr函數(shù),1.4.4版本中拒絕從TextNode和CommentNode上獲取屬性,在1.5版本中添加了一個AttributeNode(noteType == 2)。
在1.4.4版本中,jQuery會在頁面unload的時候清理掉由jQuery維護的所有DOM事件,這是為了避免IE的內(nèi)存泄露問題。但是在1.5中這一段代碼不見了,不知是出于什么考慮。
對于IE下使用cloneNode復制節(jié)點,會將事件也一起復制過來的問題,1.4.4中是采取復制innerHTML的方式給予解決,而在1.5中則采納了mootools團隊提供的方法,使用cloneFixAttribute函數(shù)修正該問題。
cloneFixAttribute函數(shù)們于jQuery 1.5 beta1源碼文件的5388-5438行,處理IE的BUG的原理很簡單,當然前端里一些看似簡單的東西,都是很難發(fā)現(xiàn)的:
IE中有個叫clearAttributes的函數(shù),會清除到節(jié)點上的所有屬性,順便把和事件相關的onclick之類的屬性也去掉了。在復制出來的節(jié)點上調(diào)用這個函數(shù),就會把屬性清得干干凈凈。
IE中還有一個叫mergeAttributes的函數(shù),把一個節(jié)點的屬性復制到另一個節(jié)點上,但他不會把和事件相關的屬性復制過去。所以再把原始節(jié)點調(diào)用mergeAttributes,把屬性重新放回復制出來的節(jié)點上,這就相當于起到了去除事件相關屬性的作用。
另外cloneFixAttribute函數(shù)還處理了非常多IE6-8在cloneNode上的兼容性問題,非常值得詳細研究。
AJAX部分
AJAX已經(jīng)完全重寫了,只留下一點邊邊角角保留著1.4.4版本的風采,這里只抽取一部分進行簡單的說明。
原來版本中$.get和$.post的實現(xiàn)非常相似,具體來說僅有一個method配置項不同,因此在1.5版本中被合并起來了:
$.each(['get', 'post'], function(i, method) {
$[method] = function() { ... };
});
ajaxSetup函數(shù)現(xiàn)在加了一行return this;,可以鏈式調(diào)用了。
serializeArray函數(shù)現(xiàn)在統(tǒng)一將value中的換行符替換成Windows的風格(\r\n)。
AJAX的回調(diào)函數(shù)中,作為參數(shù)的對象不再是原生的XMLHTTPRequest,而是jQuery自己封裝的稱為jXHR的對象,這個對象提供了XMLHTTPRequest的常用接口。
原本對于“請求成功”的瀏覽器狀態(tài)碼,除200-299以及304外,還有一個1223,來自于IE的一個BUG,會將204的狀態(tài)碼變成1223。現(xiàn)在因為有了jXHR對象,相當于中間多了一層,因此從jXHR對象獲取statusCode不會出現(xiàn)1223的情況,已經(jīng)被變回204了。
jQuery.ajax函數(shù)的配置項中多了一個statusCode項,其結(jié)構(gòu)為map,用于指定返回特定狀態(tài)碼時的回調(diào)函數(shù),大致形式如下:
jQuery.ajax({
url: 'xxx',
statusCode: {
200: function() { 處理請求成功 },
404: function() { 處理頁面未找到 },
503: function() { 處理Service Unavailable }
}
});
再添加了這個回調(diào)后,jQuery.ajax函數(shù)已經(jīng)有非常多的回調(diào)函數(shù),其觸發(fā)過程如下:
根據(jù)返回的狀態(tài)碼,觸發(fā)success或者error回調(diào)。
根據(jù)狀態(tài)碼,觸發(fā)對應的statusCode回調(diào)。
觸發(fā)complete回調(diào)。
觸發(fā)全局ajaxComplete回調(diào)。
如果此時沒有正在執(zhí)行的AJAX,觸發(fā)全局ajaxStop回調(diào)。
其他細節(jié)
入口函數(shù)jQuery.fn.init現(xiàn)在多了一個參數(shù),值始終為rootjQuery,用于加速init函數(shù)中對rootjQuery變量的查找速度(減少了一層作用域):
//jQuery 1.5 beta1 源碼23行
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}jQuery對象支持繼承了,具體的修改是將幾處直接調(diào)用jQuery的代碼改為了對this.constructor的調(diào)用:
202行:return this.constructor( context ).find( selector );
253行:var ret = this.constructor();
334行:return this.prevObject || this.constructor(null);同時還提供了jQuery.subclass函數(shù)用于創(chuàng)建一個繼承自jQuery的類型,由于不是很常用jQuery,更是從來沒有用到過需要繼承jQuery的情況,因此也不方便說這個功能的作用有多大。
jQuery._Deferred和jQuery.Deferred
首先不得不說這兩個新生事物,因為他們是作為基礎設施存在,不把這兩個東西講明白了,有些問題根本沒辦法解釋。
首先,jQuery.Deferred是jQuery._Deferred的增強版,因此對于這個問題,從jQuery._Deferred入手,就能說明一大半的問題。
什么是Deferred?從字面上看,我的第一反應是“延遲加載”,首字母大寫的應該是“類型”的定義,所以這大概是一個“透明提供延遲加載功能”的類型吧。然而實際上,雖然確實帶有那么一點點“延遲”的意思,這個東西卻不是用來實現(xiàn)延遲加載的。
簡單來說,jQuery._Deferred是一個函數(shù)隊列,他的作用有以下幾點:
保存若干個函數(shù)。
在特定的時刻把保存著的函數(shù)全部執(zhí)行掉。
執(zhí)行過后,新進來的函數(shù)會立刻執(zhí)行。
感覺是不是和啥東西很像?對,jQuery的ready函數(shù)就是這樣的邏輯,實際中jQuery 1.5中的ready函數(shù)也確實被嫁接到這上面去了。
jQuery._Deferred提供下面的接口:
done:function(fn1, fn2, ...)的形式,用于把函數(shù)添加到隊列中。
fire:function(context, args)的形式,使用context指定this對象,args指定參數(shù),調(diào)用隊列中所有函數(shù)。fire被調(diào)用后,_Deferred會進入isResolved狀態(tài),未來對done的調(diào)用不會再保存函數(shù),而是直接調(diào)用函數(shù)。
resolve:相當于調(diào)用fire(this, arguments),一個簡化的方法。
isResolved:用來判斷_Deferred是否在isResolved狀態(tài),具體參考前面的fire函數(shù)的解釋。
cancel:取消掉整個隊列,這樣不管未來是不是fire,隊列中的函數(shù)都不會再被調(diào)用。
說明白了jQuery._Deferred,再來看看jQuery.Deferred。這個東西其實就是2個_Deferred組成的,第一個稱為deferred,用于保管“正常”狀態(tài)下的函數(shù);第二個稱為failDeferred,用于保管“出錯”狀態(tài)下的函數(shù)。同時jQuery.Deferred提供了一些新的接口:
then:function(done, fail)的形式,把done添加進deferred,把fail添加進failedDeferred。
fail:相當于failDeferred的done函數(shù)。
fireReject:相當于failDeferred的fire函數(shù)。
reject:相當于failDeferred的resolve函數(shù)。
isRejected:相當于failDeferred的isResolved函數(shù)。
同時jQuery.Deferred取消了cancel函數(shù)。
那么這個是啥用的呢?有“正?!焙汀俺鲥e”2個狀態(tài),同時又是異步的,很容易就能想到……對,給AJAX用的,在下一篇分析中再詳細說明。
jQuery.ready的變化
因為有了jQuery._Deferred這個東西,jQuery.ready函數(shù)變成依賴于函數(shù)隊列,具體的變化有:
原來的readyList變量已經(jīng)不再是一個數(shù)組,而變成了jQuery._Deferred對象。
原本在DOMContentLoaded時,調(diào)用readList中所有函數(shù)的邏輯,現(xiàn)在也使用了jQuery._Deferred中,原來的代碼:
復制代碼 代碼如下:
while ( (fn = ready[ i++ ]) ) {
fn.call( document, jQuery );
}
變成了:
復制代碼 代碼如下:
readyList.fire( document , [ jQuery ] );
jQuery.parseXML函數(shù)
新增了靜態(tài)函數(shù)jQuery.parseXML,用于提供瀏覽器兼容的從字符串轉(zhuǎn)為XML文檔的功能。
該函數(shù)的邏輯網(wǎng)上有很多,jQuery也沒有特別的地方,大致分為以下2種:
對于標準瀏覽器,使用DOMParser對象:
復制代碼 代碼如下:
var parser = new DOMParser();
var xml = parser.parseFromString(text, 'text/html');對于IE,使用Microsoft.XMLDOM對象:
var parser = new ActiveXObject('Microsoft.XMLDOM');
parser.async = 'false';
parser.loadXML(text);
var xml = parser.documentElement;
data部分
添加了jQuery.hasData函數(shù),用于判斷一個元素是否有jQuery附加上去的數(shù)據(jù)。
修改了jQuery.expando的實現(xiàn),在原來單純地取當前時間的基礎上,添加了一個隨機數(shù):
expando = "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" );這樣保證在同一時間,引入多個jQuery副本,這幾個副本之間的expando不會相互沖突,導致元素上的data變得錯亂。一般來說,是不會引入多個jQuery副本的,但是使用SealJS等的時候,配置不當?shù)脑?,也是很容易出現(xiàn)此類問題的。
DOM操作部分
原本的hasClass、addClass、removeClass函數(shù)都需要將元素的class屬性分隔為數(shù)組,在1.4.4版本中,通過\n或\t進行分隔,在1.5中增加了一個\r,用于對應Windows平臺下的換行符(\r\n)。
jQuery.fn.attr函數(shù),1.4.4版本中拒絕從TextNode和CommentNode上獲取屬性,在1.5版本中添加了一個AttributeNode(noteType == 2)。
在1.4.4版本中,jQuery會在頁面unload的時候清理掉由jQuery維護的所有DOM事件,這是為了避免IE的內(nèi)存泄露問題。但是在1.5中這一段代碼不見了,不知是出于什么考慮。
對于IE下使用cloneNode復制節(jié)點,會將事件也一起復制過來的問題,1.4.4中是采取復制innerHTML的方式給予解決,而在1.5中則采納了mootools團隊提供的方法,使用cloneFixAttribute函數(shù)修正該問題。
cloneFixAttribute函數(shù)們于jQuery 1.5 beta1源碼文件的5388-5438行,處理IE的BUG的原理很簡單,當然前端里一些看似簡單的東西,都是很難發(fā)現(xiàn)的:
IE中有個叫clearAttributes的函數(shù),會清除到節(jié)點上的所有屬性,順便把和事件相關的onclick之類的屬性也去掉了。在復制出來的節(jié)點上調(diào)用這個函數(shù),就會把屬性清得干干凈凈。
IE中還有一個叫mergeAttributes的函數(shù),把一個節(jié)點的屬性復制到另一個節(jié)點上,但他不會把和事件相關的屬性復制過去。所以再把原始節(jié)點調(diào)用mergeAttributes,把屬性重新放回復制出來的節(jié)點上,這就相當于起到了去除事件相關屬性的作用。
另外cloneFixAttribute函數(shù)還處理了非常多IE6-8在cloneNode上的兼容性問題,非常值得詳細研究。
AJAX部分
AJAX已經(jīng)完全重寫了,只留下一點邊邊角角保留著1.4.4版本的風采,這里只抽取一部分進行簡單的說明。
原來版本中$.get和$.post的實現(xiàn)非常相似,具體來說僅有一個method配置項不同,因此在1.5版本中被合并起來了:
復制代碼 代碼如下:
$.each(['get', 'post'], function(i, method) {
$[method] = function() { ... };
});
ajaxSetup函數(shù)現(xiàn)在加了一行return this;,可以鏈式調(diào)用了。
serializeArray函數(shù)現(xiàn)在統(tǒng)一將value中的換行符替換成Windows的風格(\r\n)。
AJAX的回調(diào)函數(shù)中,作為參數(shù)的對象不再是原生的XMLHTTPRequest,而是jQuery自己封裝的稱為jXHR的對象,這個對象提供了XMLHTTPRequest的常用接口。
原本對于“請求成功”的瀏覽器狀態(tài)碼,除200-299以及304外,還有一個1223,來自于IE的一個BUG,會將204的狀態(tài)碼變成1223。現(xiàn)在因為有了jXHR對象,相當于中間多了一層,因此從jXHR對象獲取statusCode不會出現(xiàn)1223的情況,已經(jīng)被變回204了。
jQuery.ajax函數(shù)的配置項中多了一個statusCode項,其結(jié)構(gòu)為map,用于指定返回特定狀態(tài)碼時的回調(diào)函數(shù),大致形式如下:
復制代碼 代碼如下:
jQuery.ajax({
url: 'xxx',
statusCode: {
200: function() { 處理請求成功 },
404: function() { 處理頁面未找到 },
503: function() { 處理Service Unavailable }
}
});
再添加了這個回調(diào)后,jQuery.ajax函數(shù)已經(jīng)有非常多的回調(diào)函數(shù),其觸發(fā)過程如下:
根據(jù)返回的狀態(tài)碼,觸發(fā)success或者error回調(diào)。
根據(jù)狀態(tài)碼,觸發(fā)對應的statusCode回調(diào)。
觸發(fā)complete回調(diào)。
觸發(fā)全局ajaxComplete回調(diào)。
如果此時沒有正在執(zhí)行的AJAX,觸發(fā)全局ajaxStop回調(diào)。
其他細節(jié)
入口函數(shù)jQuery.fn.init現(xiàn)在多了一個參數(shù),值始終為rootjQuery,用于加速init函數(shù)中對rootjQuery變量的查找速度(減少了一層作用域):
//jQuery 1.5 beta1 源碼23行
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}jQuery對象支持繼承了,具體的修改是將幾處直接調(diào)用jQuery的代碼改為了對this.constructor的調(diào)用:
202行:return this.constructor( context ).find( selector );
253行:var ret = this.constructor();
334行:return this.prevObject || this.constructor(null);同時還提供了jQuery.subclass函數(shù)用于創(chuàng)建一個繼承自jQuery的類型,由于不是很常用jQuery,更是從來沒有用到過需要繼承jQuery的情況,因此也不方便說這個功能的作用有多大。
相關文章
jquery實現(xiàn)簡單合攏與展開網(wǎng)頁面板的方法
這篇文章主要介紹了jquery實現(xiàn)簡單合攏與展開網(wǎng)頁面板的方法,通過簡單的jquery頁面元素樣式操作實現(xiàn)展開與合攏面板的功能,非常簡單實用,需要的朋友可以參考下2015-09-09