2.22 支持的浏览器及代码差异化
支持的浏览器
JS API基于两种软件运行体系来进行封装,一种是使用ActiveX控件版本的SDK原生API进行封装;另一种是采用了跨浏览器通信插件的API进行封装。这样可以使JS API从根本上支持更多的浏览器。
目前的支持情况如下表:
IE8 | IE11 | Google Chrome | Microsoft Edge(旧版) | Microsoft Edge(新版) | FireFox |
---|---|---|---|---|---|
不支持 | 支持 | 支持 | 不支持 | 支持(尚存问题) | 暂不支持 |
不同浏览器间的通信机制
首先造成代码差异化的原因是:IE下的SDK的通信机制是同步的,即方法调用,获得结果,结果继续传递给下个方法,列举如下:
// IE下的常规调用模式
// 调用get()获取变量a的值
var a = get();
// 将变量a的值作为参数传给set()方法,并获得变量b的值
var b = set(a);
// 将变量a与变量b的值相加的结果作为参数传给cal()方法,并获得结果变量c的值
var c = cal(a + b);
在非IE浏览器下,SDK的通信机制是异步的,即方法调用,等待结果,获得结果后,继续传递给下个方法,列举如下:
// 非IE下的常规调用模式
// 调用get()获取变量a的值
get(function(a){
// 将变量a的值作为参数传给set()方法,并获得变量b的值
set(a, function(b){
// 将变量a与变量b的值相加的结果作为参数传给cal()方法,并获得结果变量c的值
cal(a + b, function(c){
//输出c...
console.log(c);
});
});
});
可以发现,异步通信下的写法非常繁琐,同时让人不好理解。
JS API为了让开发者在不同浏览器上运行CooSDK时,对代码的改动量达到最小,因此在内部做了大量的针对性处理,尽可能少的使用异步处理,但不可避免的是,这种异步机制是贯穿代码运行始终的,开发者仍需知道有这么一种机制,才能在使用JS API时不存在认知性障碍。
API对象剖析
举一个JS API中常用的对象PositionObj的例子,对其进行深度的剖析。
该对象的构造函数实现大致如下:
function PositionObj(x, y, z) {
this._x = x;
this._y = y;
this._z = z;
this._map = null;
this._position = null;
try {
if (Element.prototype.CooGisSDKCtrl) {
this._map = Element.prototype.Map;
} else {
this._map = document.getElementById("CooRunSDK").GetIMapMgrPtr();
}
} catch (e) {
console.log("PositionObj failed");
}
if (defined(this._map)) {
this._position = this._map.CreatePosition(this._x, this._y, this._z);
}
}
可以发现构造函数里调用了原生API的 CreatePosition 方法,这个方法创建了一个IPositionPtr对象,该对象内含GetX(),GetY(),GetZ()这三个方法。因此PositionObj的x、y、z属性,实质上是分别调用了GetX(),GetY(),GetZ()这三个方法来获得的。
我们用JS API写个简单的例子:
var posA = new CooSDK.PositionObj(120, 30, 0);
var posB = new CooSDK.PositionObj(posA.x, posA.y, posA.z + 10);
将其实际的API流程代入后,是这样子的:
var posA = new CooSDK.PositionObj(120, 30, 0);
var posB = new CooSDK.PositionObj(posA.position.GetX(), posA.position.GetY(), posA.position.GetZ() + 10);
在IE浏览器下,这是同步的通信调用方式,这种写法不存在任何问题。
但在非IE浏览器下,其处于异步的通信调用方式,拿下面的写法来举例:
var posB = new CooSDK.PositionObj(posA.position.GetX(), posA.position.GetY(), posA.position.GetZ() + 10);
在非IE浏览器中,此时posA.position.GetX()的返回值并不是x,而是JS API临时生成的一个具有唯一id标识的对象,以此类推,可以发现
posA.position.GetZ() + 10
这句话会产生明显的问题,object对象+数字是错误的语法。所以得换成异步的写法:
posA.position.GetZ(function(z){
var posB = new CooSDK.PositionObj(posA.position.GetX(), posA.position.GetY(), parseFloat(z) + 10);
});
我们再假设一种情况,即posA.position.GetZ()不加减值了,写法如下:
var posB = new CooSDK.PositionObj(posA.position.GetX(), posA.position.GetY(), posA.position.GetZ());
这种写法在非IE浏览器下也是支持的,但细心的人会发现,PositionObj构造函数需要的是数值类型的参数,才能成功创建对象,在这里传入的都是对象,为何能这么写也是可以的?其实在这里,SDK跨浏览器插件内部做了相应的处理,根据传入的对象唯一id找到SDK对应存储区域的值,进行了后台处理,因此开发者也是可以这么写的,避免了大量的异步写法。
由此根据上述内容总结,开发者在非IE浏览器下开发时,需要注意通信机制本质上的变化,JS API已经尽可能的封装了实现细节,降低代码变化的感知。这些改变在API文档中会有大量的体现,主要体现在调用接口获得返回值的流程是异步的,需要在回调里进行处理,开发时务必关注这类参数变化。