摘要:图对可复用代码挑战最大的五项问题五大开发问题如下。浏览器的缺陷修复。浏览器缺失的功能。复杂的地方是,当前浏览器会在未来的浏览器版本中被修复。假设浏览器引起常见的网站问题为解决浏览器使用特殊技巧,将来浏览器发布新版本修复了,就会出现问题。
任意一段重要的代码都需要关注无数的开发问题。但是,其中对可复用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
发生了什么呢?
浏览器将
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/109397.html
目录 一、禅道 一、测试工具背景 二、测试管理工具 三、测试工具介绍 四、禅道介绍 五、禅道操作 7. 创建发布 8. 测试团队 二、缺陷报告 三、测试报告 一、概要 二、测试过程 三、缺陷分析 四、测试总结 四、接口测试以及用例编写 五、Fiddler 好文推荐 一、禅道 一、测试工具背景 当测试环境搭建完成后,测试人员将在自己搭建的环境上执行测试用例,开展测试工作。测试人员在执行测试用例的过...
摘要:如果数据从旧系统迁移到新系统是当前版本发布的主要目的,那么更要关注报表数据数据迁移缺陷如果一个旧系统要被新系统取代,旧系统里的数据要移到新系统。 对任何软件产品来说,软件上线永远是一件大事。完全确保所有功能生效以及发布高质量软件给用户非常重要。 不好的、不成熟的、不稳定的、难以使用的产品会引...
阅读 577·2023-04-25 21:29
阅读 1104·2023-04-25 21:27
阅读 1043·2021-11-25 09:43
阅读 1075·2021-09-29 09:43
阅读 3612·2021-09-03 10:30
阅读 2852·2019-08-29 15:26
阅读 2801·2019-08-29 12:52
阅读 1739·2019-08-29 11:10