摘要:圖對可復用代碼挑戰最大的五項問題五大開發問題如下。瀏覽器的缺陷修復。瀏覽器缺失的功能。復雜的地方是,當前瀏覽器會在未來的瀏覽器版本中被修復。假設瀏覽器引起常見的網站問題為解決瀏覽器使用特殊技巧,將來瀏覽器發布新版本修復了,就會出現問題。
任意一段重要的代碼都需要關注無數的開發問題。但是,其中對可復用JavaScript代碼挑戰最大的五項問題如圖14.2所示。
圖14.2 對可復用JavaScript代碼挑戰最大的五項問題
五大開發問題如下。
瀏覽器缺陷。
瀏覽器的缺陷修復。
外部代碼。
瀏覽器回歸。
瀏覽器缺失的功能。
我們需要權衡解決這些問題所花費的時間與得到的收益。這些是不得不回答的問題。你分析潛在受眾、開發資源、開發排期等,這些都是決定性因素。
當試圖開發可復用的JavaScript代碼,我們需要考慮所有的因素,還需要考慮目前最流行的瀏覽器,因為這些瀏覽器是我們的目標受眾最可能使用的瀏覽器。其他不那么流行的瀏覽器,我們至少保證代碼可以優雅降級。例如,如果一個瀏覽器不支持某API,我們應該小心我們的代碼不會拋出任何異常,這樣剩下的代碼仍然可以順利執行。
在接下來的小節中,我們將講解這些問題,以便更好地理解我們面對的挑戰以及如何應對。
1 瀏覽器的bug和差異當我們開發可復用性JavaScript代碼時,需要考慮解決的問題之一是處理我們確定需要兼容的多種瀏覽器bug以及API的差異。盡管瀏覽器越來越標準化,但是代碼還是必須得完全符合瀏覽器提供的特性。
實現這一目標的方法很直接:我們需要完整的測試工具,足以覆蓋代碼常用的和不常用的用例。充分測試之后,在知道開發的代碼將在支持的瀏覽器中工作后,我們會感到安全。假設瀏覽器沒有后續變化,不會打破向后兼容性,我有一個模糊的預感,代碼甚至會在未來版本的瀏覽器中工作。在14.3節中,我們會觀察特定的策略來處理瀏覽器bug和差異。
復雜的地方是,當前瀏覽器bug會在未來的瀏覽器版本中被修復。
2 瀏覽器的bug修復瀏覽器永遠存在特定的錯誤是很愚蠢的——大部分瀏覽器bug最終都會修復,把希望寄托在瀏覽器bug上是很危險的開發策略。最佳方式是使用14.3節中的技術,使用不會過時的變通方案。
在編寫一個可重用的JavaScript代碼時,我們希望它可以持續運行很長時間。編寫任何方面的網站(CSS、HTML等),瀏覽器發布新版本后,我們不希望再回去修復代碼。
假設瀏覽器bug引起常見的網站問題:為解決瀏覽器bug使用特殊技巧,將來瀏覽器發布新版本修復了bug,就會出現問題。
處理瀏覽器漏洞的問題是雙重的:
當bug最終被修復,我們的代碼容易損壞。
我們無法為了避免網站損壞而說服瀏覽器廠商不修復bug。
最近恰好發生了第2種情況的有趣的事例,關于scrollTop的bug(https://dev.opera.com/article...)。
當處理HTML DOM時,可以使用scrollTop和scrollLeft屬性,修改當前元素的滾動位置。但是當我們對根元素使用這些屬性時,根據規范,將會返回滾動的位置,IE11與Firefox瀏覽器嚴格遵循了這則規范。而Safari、Chrome和Opera并沒有遵守。如果試圖修改根元素的滾動位置時,不會發生任何事情。為了實現相同的效果,我們只能在body元素上使用scrollTop和scrollLeft屬性。
當面對瀏覽器的不一致性時,Web開發者們常常檢測當前瀏覽器的名字(通過用戶代理字符串,后續會詳細介紹),然后在IE11和Firefox上對HTML元素使用scrollTop和scrollLeft屬性,而在Safari、Chrome和Opera上則對body元素使用scrollTop和scrollLeft屬性。規避這類問題將會造成災難性后果。因為許多網頁明確編碼指定在Safari、Chrome或Opera上使用body元素,這些瀏覽器無法真正修復這個bug,因為一旦修復,許多網頁都無法運行。
這引出了另一個關于bug的觀念:在確定某一功能是否是潛在的錯誤時,使用規范進行驗證!
瀏覽器的bug不同于未指明的API。參考瀏覽器規范非常重要,因為規范提供了確切的標準,瀏覽器使用這些標準進行開發和完善代碼。相比之下,一個未指明的API的實現可能會在任何時候發生改變(特別是試圖成為標準化的實現)。在未指明的API不一致的情況下,你應該對預期輸出進行測試。警惕這些API未來可能發生的變化。
另外,bug修復和API的變化是有區別的。bug修復是很容易預見的——瀏覽器最終將修復bug,即使要花很長的時間,API變化更難發現。標準API不太可能改變,盡管不是完全聞所未聞,變化更有可能出現未指明的API中。
幸運的是,大多數Web應用程序出問題的情況很少發生。萬一出現問題,有效地提前預知是無效的辦法(除非我們逐一測試相關的API——但是這樣一個過程的開銷是可怕的)。這種API的變化應該做回歸處理。
下一個需要關心的問題是,沒有人是一座孤島,我們的代碼也不是,讓我們研究代碼的影響范圍。
3 外部代碼和標記任何可重用代碼必須與圍繞它的代碼共存。我們希望代碼運行在自己編寫的網站或是他人開發的網站上,我們都需要確保代碼可以與其他代碼共存。
這是一把雙刃劍:我們的代碼不僅必須能夠經受住可能寫得很遭的外部代碼,還必須得克服環境對代碼的不利影響。
我們需要警惕的程度很大程度上取決于所使用的代碼對環境的關注。例如,如果我們僅為單個或有限個網站編寫可重用的代碼,在某種程度上可以控制,可以少一些擔心,因為我們知道代碼的運行對外部代碼的影響程序,而且一旦有問題,我們可以自行修復。
{注意 }這個問題的重要程度足以用一本書來闡述。如果你想更深入地探究,我們強烈推薦Ben Vinegar 和 Anton Kovalyov 編寫的《第三方JavaScript》一書(Manning, 2013, https:// www.manning.com/books/third-party-javascript)。
如果開發代碼將廣泛用于未知環境(不可控的)中,則我們需要雙重確認代碼的健壯性。接下來討論一些實現代碼健壯性的策略。
代碼封裝為了避免我們的代碼影響頁面上的其他代碼,最佳實踐是使用封裝。通常來說,封裝指代碼(如同)存放在容器里。從廣義上來說,是一種限制訪問其他對象組件的語言機制。Aunt Mathilda也許會總結為“各人自掃門前雪,莫管他人瓦上霜”。
在頁面上引入我們的代碼時,盡可能少地影響全局代碼,將會使Aunt Mathilda非常開心。事實上,盡可能少地使用全局變量,甚至最好僅限一個,是很容易的。
第12章中的jQuery,它是最流行的客戶端JavaScript庫,也是最好的范例。jQuery引入一個名為jQuery的全局變量(一個函數),別名為$,它甚至允許其他網頁為$設置別名避免沖突。
jQuery中幾乎所有的操作都通過jQuery函數完成。其他函數(工具函數)被定義為jQuery的屬性(第3章介紹如何將函數定義為另一個函數的屬性),使用jQuery作為命名空間。我們可以使用相同的策略。假設我們需要定義一組函數,我們將其定義在命名空間ninja下。
與jQuery類似,我們可以定義名為ninja()的全局函數以操作傳入的變量。例如:
var ninja = function(){ /* implementation code goes here */ }
使用我們設定好的命名空間定義工具函數:
ninja.hitsuke = function(){ /* code to distract guards with fire here */ }
如果我們不需要ninja作為函數,僅作為一個命名空間即可,我們可以使用如下定義方式:
var ninja = {};
創建空對象,隨后在該對象上定義屬性或方法即可。為了保證代碼的封裝,需要避免其他操作,如修改已經存在的變量、函數原型甚至DOM元素。修改我們自己代碼之外的任何內容,都可能引起潛在的沖突和混淆。另外,盡管我們小心翼翼地嚴格遵守最佳實踐封裝代碼,但我們仍然無法保證代碼的行為。
模范代碼有一個老笑話Grace Hopper在Cretaceous時期為接替人員清除蛀蟲時說:“你最不惡心的代碼就是你自己寫的代碼。”看起來很諷刺,但是當我們的代碼與不可控的代碼同時運行時,為了安全起見,我們需要假設最糟的情況。
盡管一些代碼編寫工整,但也有可能潛在地做一些出乎意料的事,例如修改函數屬性、對象屬性和DOM元素的方法。這些都可能設有陷阱。
在這種情況下,我們的代碼只能做一些無傷大雅的事,例如使用JavaScript數組,一般情況下JavaScript數組只能是JavaScript數組。但是,如果一些頁面上修改了數組的行為,我們的代碼將無法運行,當然不是我們自身的原因。
遺憾的是,處理這種問題沒有固定的原則標準,但是我們可以采取一些措施。我們將在后續小節中介紹保護性方法。
應對ID濫用大部分瀏覽器具有一些反特性(我們不能稱之為bug,因為這些特性是有意而為之),這些特性會使得代碼不可預期地落入陷阱從而運行失敗。這些特性使得原始元素與添加在元素上的id或name屬性產生關聯。但是當id或name屬性與元素上已經存在的部分屬性產生沖突時,就會發生一些意料之外的情況。
查看以下HTML代碼片段,觀察id屬性的濫用:
現在,在瀏覽器中可以這樣調用:
var what = document.getElementById("form").action;
我們期望返回合理的form的action屬性。大部分情況下是可以返回的。但是當檢查值的時候你會發現,返回的卻是input#action元素。為什么?讓我們試試其他元素:
document.getElementById("form").submit();
這條語句本應引起form提交,但是卻返回script錯誤:
Uncaught TypeError: Property "submit" of object #is not a function
發生了什么呢?
瀏覽器將
這是為了兼容過去的瀏覽器的處理方法,老式瀏覽器不具備獲取DOM元素的方法。瀏覽器廠商添加這種特性是為了方便獲取form元素。現如今我們可以輕松地獲取DOM元素,但是仍然留下了副作用。無論如何,瀏覽器這種特殊的“特性”可能引起代碼中大量撲朔迷離的問題,在調試時需要謹記于心。當我們遇到屬性被意外地轉變成非預期的內容時,罪魁禍首有可能是DOM濫用。幸好我們可以在自己的代碼中避免這種問題,避免編寫有可能與標準屬性發生沖突的過于簡單的id或name屬性,并可以推薦其他開發者使用類似的策略。開發過程中尤其需要避免submit值,以免造成令人沮喪和困惑的bug行為。
樣式和腳本的加載順序通常我們期望CSS規則在代碼執行時已經可用。確保在樣式代碼中定義的CSS規則在JavaScript代碼執行時已經可用的最佳方式之一是,將外部樣式表單放置在外部腳本文件之前。如果不這樣做,可能引起意料之外的結果,因為腳本可能試圖訪問未定義的樣式信息。遺憾的是,這種問題無法通過JavaScript腳本進行矯正,只能通過手動修改用戶文件解決。
后續幾節中會介紹一些關于外部代碼對于代碼運行的影響的基礎示例。當其他用戶試圖將我們的代碼集成進他們的網站時,會暴露出一些問題,那么應該如何診斷這些問題,如何設計合適的測試用例來解決這些問題呢?有時,當我們試圖將其他人的代碼集成進自己的頁面時,會發現類似的問題,希望本節介紹的建議有助于解決這些問題。糟糕的是,對于解決代碼集成問題,除了采用一些聰明的方式來編寫防御性代碼,沒有其他更好的方式。接下來繼續關注下一個問題。
4 回歸回歸是在編寫可復用、可維護性JavaScript代碼時,遇到的最難的問題之一。因為瀏覽器的bug或不向后兼容的API發生變化(通常是未詳細說明的API)導致代碼不可預期地中斷了。
{注意 }預期的變化這里我們使用術語回歸的經典定義:過去使用的特性不再運行了。這通常是無意的,也有可能是仔細考慮后的結果。
一些API發生的可預見性的變化,我們可以提前檢測并處理,如代碼清單14.1所示。例如,Microsoft在 IE 9引入對DOM 2 的事件處理機制(使用addEventListener方法綁定事件),而過去的IE版本使用IE內置的attachEvent方法。對于 IE 9之前的代碼,使用簡單的特性檢測可以處理這種變化。
清單14.1 預期即將發生的API變化
function bindEvent(element, type, handle) { if (element.addEventListener) { element.addEventListener(type, handle, false); ?--- 使用標準API綁定 } else if (element.attachEvent) { element.attachEvent("on" + type, handle); ?--- 使用專有API } }
在本例中,不會過時的代碼提前預知Microsoft將在IE瀏覽器中引入DOM標準。使用特性檢測來判斷瀏覽器是否支持標準API,若支持,則使用addEventListener方法。如果不支持,則檢測是否支持attachEvent方法。
大部分未來的API變化是不容易預測到的,并且無法預測未來的bug。這是本書強調測試的最重要原因之一。面對不可預期的變化對我們代碼的影響,最佳實踐是在瀏覽器發行的版本中模擬測試,以快速發現問題。
使用優秀的測試套件并密切關注即將發行的瀏覽器版本是處理未來的退化問題的最佳方式。不是在開發周期中,而是在日常測試中進行。在新發行的瀏覽器版本中運行的這些測試,應該分解到開發周期中進行。
從以下網站可以獲取即將發行的瀏覽器信息。
Microsoft Edge (繼承 IE): http://blogs.windows.com/msed...。
Firefox: http://ftp.mozilla.org/pub/fi...。
WebKit (Safari): https://webkit.org/nightly/。
Opera: https://dev.opera.com/。
Chrome: http://chrome.blogspot.hr/。
勤奮很重要。因為我們無法完全預測瀏覽器未來可能產生的bug,可行的最佳方式就是對未來可能發生的情況時刻保持警惕。
瀏覽器廠商為了避免回歸問題的發生,做了很多事情。瀏覽器通常將JavaScript庫的測試套件集成進瀏覽器測試套件中,確保未來的回歸不會直接影響這些庫。雖然無法覆蓋所有的問題(肯定無法完全覆蓋),但這是一個很好的開端,表明瀏覽器廠商在盡可能地避免發生那樣的情況。
在本節中,我們介紹了開發可復用性代碼時面對的4種主要問題:瀏覽器bug、瀏覽器bug修復、外部代碼、瀏覽器回歸。
本文摘自:JavaScript忍者秘籍(第2版)
[美] John Resig(萊西格),Bear Bibeault(貝奧特),Josip Maras(馬瑞斯) 著
jQuery之父John Resig經典力作全新改版
JavaScript高手進階秘籍
全面修訂以涵蓋 ES6 和 ES7 的概念
《JavaScript 忍者秘籍(第2版)》使用實際的案例清晰地詮釋每一個核心概念和技術。本書向讀者介紹了如何掌握 JavaScript 核心的概念,諸如函數、閉包、對象、原型和 promise,同時還介紹了 JavaScript API, 包括 DOM、事件和計時器。你將學會測試、跨瀏覽器開發,所有這些都是高級JavaScript開發者應該掌握的技能。
本書包含以下內容:
使用函數、對象和閉包編寫更高效的代碼;
學會避免JavaScript應用陷阱;
使用正則表達式編寫簡潔的文本處理代碼;
使用 promise 管理異步代碼;
全面修訂以涵蓋 ES6 和 ES7 的概念。
在本節中,我們介紹了開發可復用性代碼時面對的4種主要問題:瀏覽器bug、瀏覽器bug修復、外部代碼、瀏覽器回歸。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109397.html
目錄 一、禪道 一、測試工具背景 二、測試管理工具 三、測試工具介紹 四、禪道介紹 五、禪道操作 7. 創建發布 8. 測試團隊 二、缺陷報告 三、測試報告 一、概要 二、測試過程 三、缺陷分析 四、測試總結 四、接口測試以及用例編寫 五、Fiddler 好文推薦 一、禪道 一、測試工具背景 當測試環境搭建完成后,測試人員將在自己搭建的環境上執行測試用例,開展測試工作。測試人員在執行測試用例的過...
摘要:如果數據從舊系統遷移到新系統是當前版本發布的主要目的,那么更要關注報表數據數據遷移缺陷如果一個舊系統要被新系統取代,舊系統里的數據要移到新系統。 對任何軟件產品來說,軟件上線永遠是一件大事。完全確保所有功能生效以及發布高質量軟件給用戶非常重要。 不好的、不成熟的、不穩定的、難以使用的產品會引...
閱讀 578·2023-04-25 21:29
閱讀 1104·2023-04-25 21:27
閱讀 1044·2021-11-25 09:43
閱讀 1077·2021-09-29 09:43
閱讀 3614·2021-09-03 10:30
閱讀 2854·2019-08-29 15:26
閱讀 2803·2019-08-29 12:52
閱讀 1741·2019-08-29 11:10