Qomolangma实现篇(三):兼容层设计

================================================================================
Qomolangma OpenProject v1.0


类别    :Rich Web Client
关键词  :JS OOP,JS Framwork, Rich Web Client,RIA,Web Component,
          DOM,DTHML,CSS,JavaScript,JScript

项目发起:aimingoo (aim@263.net)
项目团队:aimingoo, leon(pfzhou@gmail.com)
有贡献者:JingYu(zjy@cnpack.org)
================================================================================


一、Qomolangma的兼容层设计
~~~~~~~~~~~~~~~~~~

自Qomo Field Test3开始,系统从内核一层开始提供跨(浏览器)平台兼容的能力。Qomo试图
在不同的浏览器上提供相同(或类同)的框架层特性。

Qomo 的兼容层设计跟常见的其它系统并不一致。基于“Qomo是可拆卸可组装的”这样一个基
本思想,Qomo实现的兼容层完全可以“象插件一样增强,或者卸载”。

与一般的系统不同,Qomo基本上是基于IE 6的JScript语言特性来提供的兼容层支撑。也就是
说,如果你向Qomo的兼容层添加一个插件,那么你应该致力于“使第三方浏览器表现得跟IE6
一致”。而通常的框架可能会反过来,要求通过兼容层来使得框架表现得跟ECMA-JavaScript
一致。Qomo没有选择这样做,只是因为Qomo原本就更接近于IE,而非其它。

事实上,我要说明的是,让框架兼容IE,比让IE上的JScript兼容ECMA更难。因为JScript提供
了很多ECMA不具备的特性。也就是说,Qomo选择了这种兼容设计,意味着实现一个更强的Java-
Script环境。而不是“让IE的JScript表现起来更象JavaScript”。


Qomo上的兼容层设计,已经使Qomo可以正常地在IE5.0中运行了。此外,你会发现,Qomo已经在
以下系统上被测试,并得到良好的支持:
  - 以Mozilla(Geckco engine)为内核的浏览器环境,例如Firefox
  - Mac上的safari
  - Windows平台上的IE5.0, IE5.5, IE6.0, IE7.0(beta1&2)

(注: 目前Qomo仅是在JavaScript层面上解决了兼容层问题。对于DOM,Qomo还没有展开设计。)


二、Qomolangma的兼容层框架
~~~~~~~~~~~~~~~~~~

在Qomo的上一个Field Test中,兼容代码和unicode相关的解码是放在system.js中的。但后来
Qomo团队发现这种设计导致system.js结构非常不清晰,移植性也极差。因此,在Field Test3
之后的版本中,兼容层被抽取出来,用独立的“兼容层框架”来导入兼容代码。此外,unicode
相关的解码被放置到与具体版本相关的“兼容代码”中。

作为一项参考,Qomo的标准设计环境中是这样:IE 5.5+浏览器。在这种环境下,透过兼容层:
支持:
Geckco engine 1.8.0.1
---------
Mozilla firefox 1.5.0.1以后
  - 没有unicode解码特性,因此要求HTML&JS使用UTF-8编码
  - 使用相对路径系统(因为浏览器对(本地)绝对路径做出了严格的安全限制)


Internet Explorer
---------
IE5, 5.5, 6.0及以后
  - 自动、智能地支持unicode解码特性。但对于IE5.0使用特殊的解码方案
  - 使用绝对路径系统,对路径/命名空间的识别和支持更准确和完善

Qomolangma通过在system.js中导入Compat/CompatLayer.js来装载兼容性框架。CompatLayer.js
用于实现:
  - 识别浏览器及版本
  - 载入指定版本浏览器的兼容代码


三、Qomolangma如何识别浏览器及版本
~~~~~~~~~~~~~~~~~~

当然,大多数浏览器相关的书籍都要求分析navigator.userAgent字符串来识别浏览器及版本。
但是Qomo没有(完全)采用这种设计。Qomo使用了一种被称为“Object Sniffing”的、准确而高
效的技术来实现浏览器的识别。在CompatLayer.js头部的注释中,你可以看到与之相关的信息。

但是Object Sniffing还是有力所不逮之处。例如识别Firefox v1.5.0与v1.5.0.1。这两个版本
只修正了一些极细微的bug。因此Object Sniffing是不能识别的。这种情况下,Qomo仍然使用
分析userAgent的技术。为此,Qomo提供了一个内置于CompatLayer.js中的checkit()函数。你
可以看看这个有趣的设计:checkit(v1, v2)返回-1/0/1之一,用于表现v1“小于/等于/大
于”v2。

CompatLayer.js设计了一个checker对象,它的属性就是浏览器版本标识。例如“ie6、ie5”
之类:
  checker = {
    ie6 : ie && document.compatMode,
    ie55 : ie && !this.ie6 && [].push,
    // ...
  }

而后面的表达式是检测该版本的代码。


四、Qomolangma中载入指定版本浏览器的兼容代码
~~~~~~~~~~~~~~~~~~

如果checker.<versionTag>条件为真,则一段相应的兼容代码被自动载入。这段代码的文件
名约定为“common_<versionTag>.js”。

一个低版本的兼容代码只需要实现兼容更高版本浏览的代码,最后再载入高版本的兼容层
即可。例如common_ie5.js未尾就载入了common_ie55.js,而后者再载入common_ie6.js。
这样的设计,使得ie6的环境中不需要载入任何“无关的(非必须的)”兼容代码。


五、兼容层代码的特点与问题
~~~~~~~~~~~~~~~~~~

Qomo的兼容层充分地考虑了可扩展性。并为后续代码中使用这种载入机制提供了可能:在
可以通过$import.get('browser')来取得浏览器版本标识“versionTag”。

Qomo兼容层在IE中实现到for IE5.0的兼容,但也付出了巨大的牺牲。这包括:
  - common_ie5.js巨大,且实现不完整
  - 不能使用"<property> in <Object>"语言来检测属性是否存在,因为IE5不支持该语法
  - 实现了IE5中的RegExp的$x属性和相关特性(例如支持函数的String.replace),但效率
    较差,因此IE5的unicode解码只能采用vbs_JoinBytes()。这也使common_ie6.js出现了
    冗余设计。

Qomo通过对IE5兼容的研究,提出了在Mozilla(firefox)、Opera、safari等浏览器中实现面
向IE6提供JavaScript兼容特性的通用方法。例如在common_safari.js等中可以看到RegExp的
兼容实现。

Qomo发现了一些与浏览器版本或内核引擎相关的严重BUG。例如只支持firefox 1.5.0.1以后
版本,并非是Qomo采用了何种特殊的、非ECMA特性的JavaScript语法,而仅仅是因为此前的
Firefox(以及采用早于Geckco 1.8.0.1的Mozilla系列引擎的浏览器)存在严重的BUG。

同样,在兼容层中的一些设计,例如common_mozold.js和common_safari.js中对execScript()
的实现。也仅仅是一些未被修正的浏览器BUG导致的代码开销。

与此相同的,是在IE5上著名的RegExp.lastIndex BUG,这使得common_ie5.js只能用substr()
去分隔字符串,以实现RegExp.replace()。——尽管这是低效的根源。

这些问题与Qomo使用怎样的兼容方案无关。因此我们只能寄期望于用户使用更新的、没有BUG
的浏览器。——再或者,忍受bug修补代码所带来的效率开销。:(

原文地址:https://www.cnblogs.com/encounter/p/2188710.html