javascript 操作流——回調的回調

來源:互聯網
上載者:User

操作流是應對一個函數的執行依賴於多個非同步作業的結果而產生的。這其實是事件派發的一種。用IE only的寫法如下:

            document.attachEvent("onclick",function(){                alert("fire click");            });            var e = document.createEventObject();            document.fireEvent("onclick",e);

用jQuery的寫法如下:

$(document).click(function(){  alert("fire click");}).trigger("click")

jQuery還能對應自訂事件,不過所有庫的自訂事件實現也別無二致。但這種事件派發只能針對當前指定的某個事件,有時我想,這些自訂事件有沒有必要存在。

比如一個遊戲,要通過QTE來打BOSS,如S+D+F,用jQuery實現如下:

             var keys = 0, keystateTime = 0;            function checkInterval(){                if(!keystateTime){                    keystateTime = new Date;                }else{                    var now = new  Date - keystateTime;                    if(now > 500){                        keystateTime = keys = 0;                    }                }            }            $(document).bind("keypress",function(e){                if(e.which === 115 || e.which === 100 || e.which === 102){//SDF                    keys += e.which;                    checkInterval();//熱鍵的每個操作之間間隔應該很小                    dom.fire("qte")                }            });              $(document).bind("qte",function(e){                if(keys === 115+100+102 && keystateTime){                   console.log("開始攻擊")                }            });

我們不能說qte事件依賴於keypress事件,準確來說,是attack這步操作依賴於三次滿足條件的按下操作。keypress綁定只是更前期的準備而已。真正相關聯的是在回調與回調之間。qte的回呼函數是上面那三個回調的回調。如果把事件函數的回呼函數當成一次操作。那麼它們四個就是一個操作流。hotKey在這過程中保是一個標識,用於移除與派發的標識。

好了,下面正式進入主題。

使用已有資源,對已有事、物進行加工改造,使之產生目標結果的過程叫操作。

操作分為兩大類:同步操作與非同步作業。同步操作,如setStyle,getAttribute, el.innerHTML= "XXX"就是同步的。非同步作業見各種事件,setTimeout回調。

同步操作是即時的,阻塞的,必然會發生的。非同步作業是延遲的,非阻塞的,不可預期的。

事件是指經過分類,擁有相同特性的導步操作的統稱。這個類別名,就是它們的事件名,click, keypress, resize, scroll....

已存的事件系統都沒有針對這種複雜的回調情況設定對應的API,不過也不奇怪,許多javascript架構都是由其他語言出身的高手的寫的,他們的思維是過程式或OO式,而不是函數式。非同步編程在其他語言也沒有像JS那麼突出,像瀏覽器需要處理資源的載入,因此自頂向下的同步編程風格必然被回調風格所代替。如果一個回調依賴於另一個回調的結果,那麼我們就陷入回調套嵌的泥沼了。

因此要解決這問題,必須要有一個機制,能實現多路監聽收集過程中的每個回調的結果觸發最終回調。這個過程是不是與模組載入系統非常像。模組載入的過程,通過require方法請求多個相依模組,將每個請求回來的模組的結果裝配到架構中,待到所有依賴都存在於框加中時就執行最終回調。

下面是我實現操作流的一些API介紹

  • 通過var flow = dom.flow(names,fn,reload)Factory 方法產生一個操作流,有沒有參數無所謂,反正也是調用原型上的bind方法。
  • flow.bind(names,fn,reload),實現多路監聽,names為一個用逗號或空格隔開的字串,每個單詞為要監聽的操作,
    fn為最後的回調。reload為布爾,為false時,比如最後回調依賴於其他四種回調,一旦這四個回調都成功執行後,就執行最後回調,以後此四種回調每次執行,都會立即執行最後回調;若為true,則要重新再執行這四次回調才又執行最終回調。不寫預設為false。
  • flow.fire(name,ret),用於觸發最後的回調,name為names中的某一單詞,ret可選,它將成為最終回調的參數之一。
  • flow.unbind(names,fn),移除監聽,fn可選,不存在則移除names對應的所有回調。

好了,我們再回顧上面的QTE實現,其實現也不嚴謹,因為玩家可能一下子ASDFG都按了。另外,我們還要保證按鍵順序,第一次必須是S,第二次是D,第三次是F。因此這種情況,使用操作流實現最合適了。上面遊戲的QTE實現用mass Framework實現如下:

             dom.require("ready,node,event,flow",function(){                var keystateTime = 0, i = 0;                function checkInterval(){                    if(!keystateTime){                        keystateTime = new Date;                    }else{                        var now = new  Date - keystateTime;                        if(now > 500){                            keystateTime =  0;                        }                    }                }                var flow = dom.flow("0_115,1_100,2_102", function(){                    if( keystateTime){                        i = -1;                        dom.log("開始攻擊")                    }                },true);                dom(document).bind("keypress",function(e){                    checkInterval();                    dom.log(i+"_"+e.which)                    flow.fire(i+"_"+e.which);                    i++                    if(i == 3 || e.which === 13  ){//按enter鍵重試                        i = 0;                    }                });            });

操作流有許多好處,我能說的大概被另一個類似實現EventProxy的作者說了,什麼避免回調套嵌,將串列等待變成並行等待,一處合并,多處觸發……EventProxy與我的操作流解決相同的問題,不同的是實現手段,我的操作流只是我的模組載入系統的簡化版,使用依賴列表對應的對象的state的值來判定是否執行最後的回調,而EventProxy則由times決定是否執行最後的回調。

               var event = dom.flow("1,2,3,4", function(){//這樣就完全等於EventProxy 的 assignAll API                    for (var i=0; i!=4; ++i){                        console.log(arguments[i]);                    }                });                console.log("first");                event.fire("1", 1);                event.fire("2", 2);                event.fire("3", 3);                event.fire("3", 3.5);                event.fire("4", 4);                console.log("second");                event.fire("1", 1);                event.fire("2", 2);                event.fire("3", 3);                event.fire("4", 4);/**first123.54second123.54123.5412341234*/

<br /><!doctype html><br /><html lang="en"><br /> <head><br /> <meta charset="utf-8" /></p><p> <title>操作流 by 司徒正美</title></p><p> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><br /> <script src="http://files.cnblogs.com/rubylouvre/dom-combine.js"></script></p><p> <script><br /> dom.require("ready,node,event,flow",function(){<br /> var keystateTime = 0, i = 0;<br /> function checkInterval(){<br /> if(!keystateTime){<br /> keystateTime = new Date;<br /> }else{<br /> var now = new Date - keystateTime;<br /> if(now > 1000){<br /> keystateTime = 0;<br /> }<br /> }<br /> }<br /> var flow = dom.flow("0_115,1_100,2_102", function(){<br /> if( keystateTime){<br /> i = -1;<br /> dom.log("開始攻擊",true)<br /> }<br /> },true);<br /> dom(document).bind("keypress",function(e){<br /> checkInterval();<br /> dom.log(i+"_"+e.which,true)<br /> flow.fire(i+"_"+e.which);<br /> i++<br /> if(i == 3 || e.which === 13 ){//按enter鍵重試<br /> i = 0;<br /> }<br /> });</p><p> });</p><p> </script><br /> </head><br /> <body><br /> <h3>操作流樣本</h3><br /> <p>請依次迅速地按下SDF!按ENTER鍵重來(如果沒有反應,請重新整理頁面)</p></p><p> </body><br /></html><br />

運行代碼

操作流大概能應對90%的非同步作業,但面對存款取款這種事務式操作,還是很無力,我考慮是否要引進“鎖”的概念。不過這是很久以後的事吧,因為一般的ORM應該能幫我們搞定這東西。介紹完畢。源碼放在github上,自己去看。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.