在IE8下的eval是不支持下面两种的用法的,很杯具,都会提示“对象不支持此属性或方法”的错误。说到这个,还发现一点很容易造成失误的地方:在浏览器解析过的script中的代码,浏览器不会重新对该script标签内的行内脚本、外联脚本执行,就算是重新给script标签定义行内脚本或者修改它的src来链接到其他的javascript脚本,浏览器都不会重新解析。
//第一:
eval("onmessage=function(str){alert(str);}");
onmessage("shllo");
//第二:
var s = document.createElement("script"),h=document.getElementsByTagName("head")[0];
s.text="onmessage=function(str){alert(str);}";
h.appendChild(s);
onmessage("hello");
——————- 提IE8 eval的兼容性分界线 ——————–
从上一篇文章《
Web Worker浅析》中,我们了解到Worker的思维是跟Ajax类似的,包括它也不支持跨域调用javascript文件,这说明底层的数据交互还是跟Ajax的模式类似(也有可能就是使用了Ajax的方式)。但是由于
IE8及以下版本都不支持Worker,所以IE就不能充分利用Worker的优点来优化浏览器执行javascript代码的性能了。但是既然Worker跟Ajax类似,那么就让IE浏览器使用Ajax的方式来实现吧,这也不是不行的。
在
IE浏览器中实现Worker机制,一个比较棘手的问题是postMessage、onmessage在主页面和Worker之间的调用问题,从代码上看,主页面是通过Worker类的实例化对象来调用postMessage、onmessage,而Worker里是直接声明和调用。所以在IE里,就可以模拟Worker的操作方式了。下面是我在IE下实现的方式:
在IE下重新定义Worker类,并且带有一个postMessage方法,这样就的话不会跟支持Worker的浏览器相冲突
使用Ajax的方式来加载外联的javascript文件,并通过eval执行返回的代码
通过一个全局的字面量对象,来实现两个文件之间的数据传输
不能改变标准的Worker类的编写方式,这个是一定要做到的
从上面的几点思路出发,编写了下面的实现代码:
(function(g){
if(!document.all) return;
var xhr=function(){
var x = null;
try{
x = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){
x = new ActiveXObject("Microsoft.XMLHTTP");
}
return x;
}
g.postMessage = function(data){
g._evt_.data = data;
}
var Worker = function(url){
this.url = url;
}
Worker.prototype={
postMessage:function(data){
g._evt_={};
g._evt_.data=data;
var x=xhr(),t=this;
x.open("GET",this.url,true);
x.onreadystatechange=function(){
if(x.readyState === 4 && (x.status === 304 || x.status === 200)){
//直接使用eval(x.responseText)在IE8下会提示错误,很奇怪,可能跟eval函数有关了
//为此不得不使用这种不太牢固的方法
eval(x.responseText.replace("onmessage","var onmessage"));
onmessage(g._evt_); //执行Worker中定义的onmessage方法
t.onmessage(g._evt_); //执行主页面中的onmessage方法
g._evt_ = null;
}
}
x.send();
}
}
g.Worker = Worker;
})(this);
在使用上有一点得注意,虽然在代码上没改变,但是在主页面中postMessage和onmessage的顺序得保持:先写onmessage、接着写postMessage方法,主要是为了在IE下能兼容。比如:
var worker = new Worker("ieworker.js");
worker.onmessage = function(evt){
alert(evt.data);
}
//注意postMessage方法一定要在onmessage后面声明,否则会导致代码只会有一次有效。
worker.postMessage("supersha");
到目前为止,测试还算良好,《
测试页面》,在各个
浏览器下都能够跑起来。
目前这个只是个简单的实现方案,代码上还是比较简单的,有待进一步的完善……
via:
ilovejs