<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    emu in blogjava

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      171 隨筆 :: 103 文章 :: 1052 評(píng)論 :: 2 Trackbacks
    如果不用xmlhttp方式獲取json數(shù)據(jù),一般我們最好用的方式是用script標(biāo)簽直接引用需要的腳本。但是不像xmlhttp可以很容易的把請(qǐng)求數(shù)據(jù)腳本和請(qǐng)求到的數(shù)據(jù)綁定到一起,script標(biāo)簽本身是無法獲知自己獲得了什么數(shù)據(jù)的,這個(gè)問題上一般使用的解決方案有:

    1 事先約定前后臺(tái)接口。這樣帶來了很強(qiáng)的前后臺(tái)偶合,后臺(tái)程序需要知道前臺(tái)想要做什么,接口很難一致化,一般不同的服務(wù)程序要使用不同的接口。而且如果需要同時(shí)并發(fā)調(diào)用同一個(gè)服務(wù)程序幾次,那么一樣無法解決接口沖突問題。

    2 前臺(tái)動(dòng)態(tài)生成回調(diào)接口后把接口名稱傳遞給后臺(tái)程序,后臺(tái)程序根據(jù)接受到的接口名稱動(dòng)態(tài)生成回調(diào)接口,比如google就喜歡接受callback參數(shù): 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
    這樣也是一個(gè)無奈之舉,一樣避免不了的令人生厭的前后臺(tái)偶合,只是改變了偶合的方式,前后臺(tái)需要換一種方式的約定,而且如果要解決并行多個(gè)異步回調(diào)的接口沖突問題,就要?jiǎng)討B(tài)的給每個(gè)回調(diào)函數(shù)創(chuàng)建一個(gè)個(gè)不同的名稱,此外服務(wù)程序的輸出不允許靜態(tài)化,必須有接受參數(shù)和生成回調(diào)腳本的功能。

    假如我們想要像生成靜態(tài)rss(http://api.fanfou.com/statuses/user_timeline.rss)文件一樣的生成靜態(tài)的json(http://api.fanfou.com/statuses/user_timeline.json)又不希望或者不能使用xmlhttp來拉取json字符串,而想要用一致的callback接口來回傳數(shù)據(jù),那么怎么樣才能解決接口沖突問題呢?事實(shí)上只有做到這點(diǎn),json才能真正想xml一樣變成一個(gè)純粹的數(shù)據(jù)描述方式,擺脫對(duì)具體上下文程序的依賴,讓一個(gè)數(shù)據(jù)自由的被不同目的的頁面mashup。比如說,在一個(gè)頁面上用json結(jié)合腳本技術(shù),把來自不同網(wǎng)站的相同格式的json數(shù)據(jù)合并顯示到一個(gè)頁面上。

    emu在這個(gè)問題上花費(fèi)過無數(shù)心血后最終還是放棄了,直到昨晚,舜子才終于有了突破:

    <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>


    如果需要支持錯(cuò)誤處理,就稍微麻煩一點(diǎn)了,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();//如果數(shù)據(jù)被cache,運(yùn)行到這一行的時(shí)候有可能回調(diào)已經(jīng)完成,窗口已經(jīng)關(guān)閉。
            }
        }
    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 
    = "無法連接到服務(wù)器";
                }
            }(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上運(yùn)行通過。

    這里有幾點(diǎn)說明:IE其實(shí)也可以用iframe(試試強(qiáng)行給isIE變量賦false值),不過用iframe的缺點(diǎn)是phantom click(會(huì)發(fā)出一個(gè)頁面跳轉(zhuǎn)的小聲音)和throbber of doom(應(yīng)該是指小沙漏型的下載圖標(biāo)吧?)。

    用document fragment的好處是避免了IE7默認(rèn)安全模式下面禁止ActiveX的問題。不過利用了IE的一個(gè)特點(diǎn):document fragment不append到document的dom里面的時(shí)候,也可以擁有自己的腳本運(yùn)行空間,可以用script標(biāo)簽發(fā)起請(qǐng)求。這樣用document fragment就可以比iframe使用更少的客戶端資源來完成操作。

    雖然多個(gè)版本的IE都支持這個(gè)特性,但是emu還是認(rèn)為其他非IE瀏覽器的處理更為合理,為了防止將來萬一IE fix了這個(gè)bug造成措手不及,emu準(zhǔn)備了另外兩個(gè)備用方案,一個(gè)是當(dāng)useFragment被聲明為false的情況下,可以用一個(gè)htmlfile的控件來代替(google在gmail中使用了這個(gè)控件,但是造成一些用戶在抱怨IE7下面的安全提示);另一個(gè)是如果不能用ActiveX,還可以走非IE瀏覽器的邏輯,用iframe來完成操作,但是耗費(fèi)的客戶端資源要稍微多一點(diǎn)。用iframe另外兩個(gè)的缺點(diǎn)是phantom click(會(huì)發(fā)出一個(gè)頁面跳轉(zhuǎn)的小聲音)和throbber of doom(應(yīng)該是指小沙漏型的下載圖標(biāo)吧?)。針對(duì)具體的用戶群的瀏覽器種類,上面幾種方案不用全上,看需要了。

    firefox下面的script標(biāo)簽其實(shí)支持onerror事件(可以寫在標(biāo)簽里面或者addEventListener上去),其他瀏覽器根據(jù)版本的不同對(duì)此有不同程度的支持,所以emu決定利用script標(biāo)簽可以堵塞頁面運(yùn)行過程的做法,script標(biāo)簽后面添加延遲的錯(cuò)誤處理邏輯(在正確的情形下?lián)屜惹蹇盏鬷frame的內(nèi)容來取消這個(gè)邏輯)。

    posted on 2007-07-10 10:07 emu 閱讀(3126) 評(píng)論(11)  編輯  收藏 所屬分類: DHTML和JAVASCRIPT 技術(shù)

    評(píng)論

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2007-07-18 22:22 emu
    寫了個(gè)頁面測(cè)試三種不同的創(chuàng)建document的方式的時(shí)間耗費(fèi):

    <HTML>
    <HEAD>
    </HEAD>
    <BODY>
    document fragment:<span id="t1"></span><br>
    htmlfile:<span id="t2"></span><br>
    iframe:<span id="t3"></span><br>
    <button onclick="test()">test</button>
    <SCRIPT LANGUAGE="JavaScript">
    var n = 100;
    function test(){
    var t=new Date();
    for(var i=0;i<n;i++)
    document.createDocumentFragment()
    document.getElementById("t1").innerHTML=(new Date()-t);
    if(window.ActiveXObject){
    var t=new Date();
    for(var i=0;i<n;i++)
    new ActiveXObject("htmlfile")
    document.getElementById("t2").innerHTML=(new Date()-t);
    }
    var t=new Date();
    for(var i=0;i<n;i++){
    var tt = document.createElement("IFRAME");
    tt.style.display="none";
    document.body.appendChild(tt);
    }
    document.getElementById("t3").innerHTML=(new Date()-t);
    }
    </SCRIPT>
    </BODY>
    </HTML>

    在ie上基本上是個(gè)1:10:100的比例。在firefox上iframe的速度和IE差不多,documentfragment的速度快一些,但是不能創(chuàng)建變量空間,沒有什么意義。safari創(chuàng)建documentfragment更快,可是創(chuàng)建iframe更慢了。最慘的是opera,居然每次插入不可見的iframe都會(huì)導(dǎo)致頁面重新渲染,最終瀏覽器都掛掉了。  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2008-03-11 19:45 hax
    emu同志,您的這個(gè)方法其實(shí)還是只是對(duì)最終編程者隱藏了callback的名字而已,并沒有提供多少額外的好處也。callback的名字(比如您的visitCountCallback)歸根到底是省不掉的,只是是否暴露給最終編程者的差別。

    因此您說的“事實(shí)上只有做到這點(diǎn),json才能真正想xml一樣變成一個(gè)純粹的數(shù)據(jù)描述方式,擺脫對(duì)具體上下文程序的依賴,讓一個(gè)數(shù)據(jù)自由的被不同目的的頁面mashup。比如說,在一個(gè)頁面上用json結(jié)合腳本技術(shù),把來自不同網(wǎng)站的相同格式的json數(shù)據(jù)合并顯示到一個(gè)頁面上。”其實(shí)也站不住腳。或者說,要達(dá)到這個(gè)目標(biāo)的前提是,都采用你的這個(gè)方案。問題是,如果可以都采用一種方案,那怎么樣都行,不是嗎?

    總之,只是一個(gè)callback包裝——如果要包裝的話,不用iframe這樣的技巧,其實(shí)也可以辦到。只要用你包裝好的回調(diào),沒有什么是辦不到的。  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2008-03-12 01:39 emu
    嗯,我想差別還是蠻大的。
    1 callback的名字如果暴露給最終編程者,首先如果有多個(gè)一模一樣的callback(但是其中的數(shù)據(jù)不同),難免就要相互沖突。
    2 你所說的前提如果是“用callback方式回傳數(shù)據(jù)”的話,其實(shí)這個(gè)方式現(xiàn)在是最流行的方式了。
    3 我的方案本來也不依賴iframe。只是不用iframe的話只能在IE上面用而已。  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2008-03-13 10:20 hax
    我的意思是,無論你用iframe或是只能用于ie的documentFragment(這明顯是ie的一個(gè)問題,憑什么要為任意一個(gè)新節(jié)點(diǎn)產(chǎn)生一個(gè)新的腳本scope?而且我懷疑這會(huì)引起內(nèi)存泄漏——ms的人在說memory leak的patterns那個(gè)文章里曾經(jīng)提到過由這一問題引起的內(nèi)存泄漏),所付出的代價(jià)似乎比不上得到的好處。

    因?yàn)椴挥胕frame,你也可以達(dá)到向最終編程者隱藏callback名字的目標(biāo),只需要callback是由你的框架托管和包裝起來就可以了。差別只在于,這種方式,這個(gè)callback名字會(huì)污染當(dāng)前的global上的命名空間,iframe則不會(huì),因?yàn)樗谝粋€(gè)獨(dú)立的scope里——但是付出的代價(jià)是有獨(dú)立的browserContext(包括window、document等對(duì)象)。  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2008-03-13 10:36 hax
    因此,iframe只是一個(gè)錦上添花的工具。我認(rèn)為理想的目標(biāo)是:

    1. callback名字最好是可配置的。因?yàn)槿f一有些人寫死了callback名字。。。
    2. 有些人不僅寫死了,而且不是callback({...json...}),而是var hardCodeJSON = {...json...},最好也能處理這種情況(肯定是可以做到的)。
    3. 不能每次都搞一個(gè)iframe,這樣太浪費(fèi)。iframe的唯一目的其實(shí)是搞一個(gè)獨(dú)立的scope,所以弄一個(gè)iframe就可以了。還有基于前面提到的因素,建議不要用documentFragment。

    那么在一個(gè)iframe情況下,你說的“多個(gè)一模一樣的callback”的沖突還是存在。這就需要用其他技巧解決。所以反過來,如果其他技巧解決了這個(gè)問題,那么iframe的唯一好處就是一丁點(diǎn)都不污染全局命名空間——個(gè)人來講,我認(rèn)為這個(gè)好處還是相當(dāng)有限的。

    下面說一個(gè)一般化(也就是不需要iframe)的最土的思路。原本我們插入一個(gè)<script>標(biāo)簽來讀取json。現(xiàn)在我們可以插入3個(gè)<script>。第一個(gè)做初始化,建立服務(wù)器所需要的callback函數(shù),如果有命名沖突,則把之前的那個(gè)變量保存起來。第二個(gè)還是load JSON。第三個(gè)做清理,去掉服務(wù)器所用的callback,并把之前的變量恢復(fù)起來。

    當(dāng)然這只是一個(gè)一般的描述,實(shí)際做的時(shí)候,肯定有很多問題要解決,但是從大體上看,應(yīng)該是行得通的。

      回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2008-03-13 14:38 emu
    呵呵,假如操作是串行的是行得通的,但是串行的操作本來也很容易處理命名沖突。如果操作是異步化的,并行發(fā)起的請(qǐng)求,并且請(qǐng)求的發(fā)起順序和相應(yīng)順序是沒有得到任何保證的,那么你說的“如果有命名沖突,則把之前的那個(gè)變量保存起來”能解決得了什么問題呢?
    至于內(nèi)存泄漏問題,一方面,內(nèi)存泄漏要靠工具檢查確認(rèn)是否存在,而不是靠猜它可能存在就簡單的去放棄一個(gè)做法的。二方面,就算發(fā)現(xiàn)了內(nèi)存泄漏,應(yīng)該想辦法定位到內(nèi)存泄漏的原因并解決它。最后,即使真的一時(shí)沒有辦法解決內(nèi)存泄漏,帶來的影響還是需要評(píng)估的?比如有的時(shí)候定時(shí)器調(diào)用函數(shù)會(huì)造成32byte的內(nèi)存泄漏,能解決當(dāng)然很好,不解決會(huì)有很大問題嗎?IE一關(guān)掉內(nèi)存就收回來了,用戶又不會(huì)一直開著IE三個(gè)月不關(guān)。  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2008-03-13 18:04 我佛山人
    我覺得這種方式不錯(cuò),而且我改良過之后,根本不需要建立名為visitCountCallBack的函數(shù),只需要約定var json = {...};

    演示:http://wfsr.net/temp/loadjson.html

    另外我測(cè)試發(fā)現(xiàn),firefox不支持相對(duì)路徑,safari不支持javascript:這種方法寫入iframe,需要write的  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2009-04-24 13:25 boyszz
    簡單事情復(fù)雜化的典型表現(xiàn)。  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù)[未登錄] 2009-05-20 01:14 小風(fēng)
    后臺(tái)直接吐出一個(gè)json變量似乎也可以解決:

    <?php
    echo
    ' var JSON={ ...}; ' ;
    ?>

    然后不是就可以像 jquery 請(qǐng)求返回一個(gè) json 對(duì)象一樣么?
    $.post( url, {}, function(json){
    json ....
    } ,'json' );

    好像上面也有和我想的一樣的  回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2009-05-22 11:39 emu
    IE8beta版本不支持documentFragment擁有獨(dú)立的運(yùn)行空間,正式版又解決了這個(gè)問題,因此寫了個(gè)小判斷:

    var df = document.createDocumentFragment();
    df.callback=function(){alert("documentFragment有獨(dú)立的腳本運(yùn)行空間")};
    window.callback=function(){alert("不支持documentFragment獨(dú)立腳本運(yùn)行空間")}
    var s = document.createElement("script");
    df.appendChild(s)
    s.src="javascript:'callback()'";
      回復(fù)  更多評(píng)論
      

    # re: 腳本綁定回調(diào):不可能完成的任務(wù) 2010-06-24 11:47 adv
    js + as3也可解決此種問題,缺點(diǎn)是瀏覽器需要播放器支持。
    1。先從as3注冊(cè)出一個(gè)方法供js調(diào)用,作用就是將請(qǐng)求的url轉(zhuǎn)入到as中,通過as轉(zhuǎn)發(fā)請(qǐng)求。
    3。定義js函數(shù)供as調(diào)用,來結(jié)束請(qǐng)求的返回結(jié)果和對(duì)應(yīng)的url地址
    3。擴(kuò)展as的URLLoader增加一個(gè)url屬性來標(biāo)識(shí)發(fā)生請(qǐng)求的url。
    4。將結(jié)果和對(duì)應(yīng)的url再次傳入js方法。

    如此,可以將并發(fā)請(qǐng)求的返回進(jìn)行對(duì)應(yīng)關(guān)系(并非對(duì)應(yīng)順序)。  回復(fù)  更多評(píng)論
      

    主站蜘蛛池模板: 久久久久亚洲AV成人无码网站 | 男人的天堂av亚洲一区2区| 精品一区二区三区高清免费观看 | 又大又黄又粗又爽的免费视频| 久久精品国产亚洲av高清漫画| 国内精品免费视频精选在线观看| 久久久久亚洲爆乳少妇无 | 亚洲AV成人片无码网站| 免费看又爽又黄禁片视频1000| 久久国产亚洲精品| 男人的好免费观看在线视频| 亚洲国产精品成人久久久| 国产高清免费视频| 亚洲中文字幕无码一去台湾| 成人毛片手机版免费看| 亚洲av无码专区在线观看下载 | 亚洲综合国产精品| 一二三四免费观看在线电影 | 久久精品亚洲福利| 日本免费高清视频| 亚洲精品91在线| 免费看大黄高清网站视频在线| 理论亚洲区美一区二区三区 | 亚洲精品123区在线观看| 精品国产免费一区二区| 黄网站色视频免费看无下截 | 人妻无码一区二区三区免费| 亚洲图片校园春色| 免费v片视频在线观看视频| 国产精品成人啪精品视频免费| 亚洲AV无码成人精品区在线观看| 中文字幕在线观看免费视频| 亚洲色成人网站WWW永久四虎| 国产aa免费视频| 高清一区二区三区免费视频| 亚洲中文字幕人成乱码 | 亚洲大成色www永久网站| 国产情侣激情在线视频免费看| 337P日本欧洲亚洲大胆艺术图 | 99久久免费精品国产72精品九九| 免费人成视频在线播放|