如果不用xmlhttp方式获取json数据,一般我们最好用的方式是用script标签直接引用需要的脚本。但是不像xmlhttp可以很容易的把请求数据脚本和请求到的数据绑定到一起,script标签本身是无法获知自己获得了什么数据的,这个问题上一般使用的解决方案有:
1 事先约定前后台接口。这样带来了很强的前后台偶合,后台程序需要知道前台想要做什么,接口很难一致化,一般不同的服务程序要使用不同的接口。而且如果需要同时并发调用同一个服务程序几次,那么一样无法解决接口冲突问题。
2 前台动态生成回调接口后把接口名称传递给后台程序,后台程序根据接受到的接口名称动态生成回调接口,比如google就喜欢接受callback参数: 
http://www.google.com/reader/public/javascript/user/10949413115399023739/label/officialgoogleblogs?n=10&callback=test饭否的接口也是这样的:
http://api.fanfou.com/statuses/user_timeline.json?callback=test
这样也是一个无奈之举,一样避免不了的令人生厌的前后台偶合,只是改变了偶合的方式,前后台需要换一种方式的约定,而且如果要解决并行多个异步回调的接口冲突问题,就要动态的给每个回调函数创建一个个不同的名称,此外服务程序的输出不允许静态化,必须有接受参数和生成回调脚本的功能。
假如我们想要像生成静态rss(
http://api.fanfou.com/statuses/user_timeline.rss)文件一样的生成静态的json(
http://api.fanfou.com/statuses/user_timeline.json)又不希望或者不能使用xmlhttp来拉取json字符串,而想要用一致的callback接口来回传数据,那么怎么样才能解决接口冲突问题呢?事实上只有做到这点,json才能真正想xml一样变成一个纯粹的数据描述方式,摆脱对具体上下文程序的依赖,让一个数据自由的被不同目的的页面mashup。比如说,在一个页面上用json结合脚本技术,把来自不同网站的相同格式的json数据合并显示到一个页面上。
emu在这个问题上花费过无数心血后最终还是放弃了,直到昨晚,舜子才终于有了突破:
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
function loadjs(url,callback){
    if(window.ActiveXObject){
        var df = document.createDocumentFragment();    
        df.visitCountCallBack = callback
        var s = document.createElement("script");
        df.appendChild(s)
        s.src=url;
    }else{
        var i = document.createElement("IFRAME");    
        i.callbackID = "2";
        i.style.display="none";
        i.callback=callback;
        i.src="javascript:\"<script>function visitCountCallBack(o){frameElement.callback(o)}<\/script><script src='"+url+"'><\/script>\""
        document.body.appendChild(i);
        i.contentWindow.callback = callback
    }
}
function init(){
    var spans = document.getElementsByTagName("span");
    for(var i=0;i<spans.length;i++){
        var id = spans[i].id;
        var url = "http://g2.qzone.qq.com/fcg-bin/cgi_emotion_list.fcg?uin="+id;
        var callback = function(id){ return function(data){
            document.getElementById(id).innerHTML = data.visitcount;
            }
        }(id);
        loadjs(url,callback);
    }
}
</SCRIPT>
</HEAD>
<BODY onload="init()">
123456 的访问量:<span id="123456"></span><BR>
2543061 的访问量:<span id="2543061"></span><BR>
20050606 的访问量:<span id="20050606"></span><BR>
</BODY>
</HTML>
如果需要支持错误处理,就稍微麻烦一点了,emu的做法是这样的: 
 
 
<HTML>
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
var isIE = !!window.ActiveXObject;
var useFragment=false;
function loadjs(url,callback,errcallback){
    if(isIE){
        if(useFragment){
           var df = document.createDocumentFragment();    
            df.visitCountCallBack = function(data){
                s.onreadystatechange=null;
                df=null;
                callback(data);
            }
            var s = df.createElement("SCRIPT");
            df.appendChild(s);
            s.onreadystatechange=function(){
                if(s.readyState=="loaded") {
                    s.onreadystatechange=null;
                    df=null;
                    errcallback();
                }
            }
            s.src = url;
        }else{
            var i=new ActiveXObject("htmlfile");
            i.open();
            i.parentWindow.visitCountCallBack=function(i){
                return function(d){
                    i.parentWindow.errcallback=null;
                    i=null;
                    callback(d);
                }
            }(i);
            i.parentWindow.errcallback=function(d){
                i.parentWindow.errcallback=null;
                i=null;
                errcallback(d);
            }
            i.write("<script src=\""+url+"\"><\/script><script defer>setTimeout(\"errcallback()\",0)<\/script>")
            if(i)i.close();//如果数据被cache,运行到这一行的时候有可能回调已经完成,窗口已经关闭。
        }
    }else{
        var i = document.createElement("IFRAME");    
        i.style.display="none";
        i.callback=function(o){
            callback(o);
            i.contentWindow.callback=null;
            i.src="about:blank"
            i.parentNode.removeChild(i);
            i = null;
        };
        i.errcallback = errcallback;
        i.src="javascript:\"<script>function visitCountCallBack(data){frameElement.callback(data)};<\/script><script src='"+url+"'><\/script><script>setTimeout('frameElement.errcallback()',0)<\/script>\"";
        document.body.appendChild(i);
    }
}
function init(){
    var spans = document.getElementsByTagName("span");
    for(var i=0;i<spans.length;i++){
        var id = spans[i].id;
        var url = "http://g2.qzone.qq.com/fcg-bin/cgi_emotion_list.fcg?uin="+id;
        var callback = function(id){ return function(data){
            document.getElementById(id).innerHTML = data.visitcount;
            }
        }(id);
        var errcallback = function(id){ return function(){
            document.getElementById(id).innerHTML = "无法连接到服务器";
            }
        }(id);
        loadjs(url,callback,errcallback);
    }
}
</SCRIPT>
</HEAD>
<BODY onload="init()">
123456 的访问量:<span id="123456"></span><BR>
2543061 的访问量:<span id="2543061"></span><BR>
20050606 的访问量:<span id="20050606"></span><BR>
</BODY>
</HTML>
在IE/FIREFOX/OPERA/SAFARI上运行通过。 
这里有几点说明:IE其实也可以用iframe(试试强行给isIE变量赋false值),不过用iframe的缺点是phantom click(会发出一个页面跳转的小声音)和throbber of doom(应该是指小沙漏型的下载图标吧?)。
用document fragment的好处是避免了IE7默认安全模式下面禁止ActiveX的问题。不过利用了IE的一个特点:document fragment不append到document的dom里面的时候,也可以拥有自己的脚本运行空间,可以用script标签发起请求。这样用document fragment就可以比iframe使用更少的客户端资源来完成操作。
虽然多个版本的IE都支持这个特性,但是emu还是认为其他非IE浏览器的处理更为合理,为了防止将来万一IE fix了这个bug造成措手不及,emu准备了另外两个备用方案,一个是当useFragment被声明为false的情况下,可以用一个htmlfile的控件来代替(google在gmail中使用了这个控件,但是造成一些用户在抱怨IE7下面的安全提示);另一个是如果不能用ActiveX,还可以走非IE浏览器的逻辑,用iframe来完成操作,但是耗费的客户端资源要稍微多一点。用iframe另外两个的缺点是phantom click(会发出一个页面跳转的小声音)和throbber of doom(应该是指小沙漏型的下载图标吧?)。针对具体的用户群的浏览器种类,上面几种方案不用全上,看需要了。
firefox下面的script标签其实支持onerror事件(可以写在标签里面或者addEventListener上去),其他浏览器根据版本的不同对此有不同程度的支持,所以emu决定利用script标签可以堵塞页面运行过程的做法,script标签后面添加延迟的错误处理逻辑(在正确的情形下抢先清空掉iframe的内容来取消这个逻辑)。