JavaScript系列之―同步還是非同步?

來源:互聯網
上載者:User

從今天開始,我會不週期性寫一些關於JavaScript的東西,包括語言,應用等方面。組成JavaScript系列。
如果沒有特殊的說明,這裡假定JavaScript的執行環境是在瀏覽器(browser)當中的。
今天開始第一次,討論一下同步和非同步。

曾經查詢過一些JavaScript的資訊,發現google出來的結果都是詢問JavaScript如何能夠實現非同步代碼。
而我,很不幸,查詢的卻是如何讓JavaScript實現非同步呼叫的同步(是不是挺起來很詭異)。

首先說一下JavaScript當中的非同步方法呼叫。
其實這個問題是大家經常要碰到的。而且這個實現也很簡單。我就不多說了。
給兩段代碼

setTimeout方法,他讓你的代碼在指定的時間(毫秒)之後執行指定的方法。只執行一次。
比如:
alert(1);
setTimeout(”alert(2)”, 1000);
alert(3);
代碼在執行到setTimeout的時候,會繼續執行下面的代碼(alert(3))而不會被阻塞。等待1000ms之後執行alert(2)
setInterval方法,他讓你的代碼每隔指定的時間,執行指定的方法,直到調用clearInterval
比如:
alert(1);
timer = setInterval(”alert(2)”, 1000);
alert(3);
代碼基本上和上面的相同,不同的是,每隔1000ms就會執行一次alert(2),直到調用
clearInterval(timer);
我們應該注意到setTimeout和setInterval都是window的方法。
我們可以直接使用,但是規範的還是調用window.setTimeout window.setInterval,之所以提及這個,我會在以後的JavaScript系列中繼續講解。

現在該說一下我遇到的問題了。
我現在使用dwr作為AJAX的server端引擎,在調用dwr方法的時候,需要提供一個回調方法(callback function)來接受server的返回結果。
而這個回調方法是不會被阻塞的。此時browser回啟動另外的現成處理。
這個很好理解,因為dwr的這個方法執行的時間是無法預料的,如果此時調用被阻塞,而server又花相當長的時間進行處理。那麼瀏覽器就會死在這裡。從使用者體驗的角度是根本無法接受的。
這裡的例子代碼是


ServerHandler.getString(”Weiming”, function (str) { //”Weiming”是傳回server的參數
alert(str);
}); // ServerHandler是dwr提供的server方法的interface,具體使用請參見dwr網站。
alert(1);
在執行的過程中,會先執行alert(1),然後在一個無法預料的時間後執行alert(str)。
如果一次簡單的比如hello world的調用是不會出問題的。
但是如果我要執行的一系列的dwr function是有前後順序的,比如後面執行的需要前面的返回結果,簡單的代碼書寫順序是無法保證執行順序的。
var myID = null;
ServerHandler.getID(function (id) {
myID = id; //無法預料何時會執行這句話
});

ServerHandler.getUserWithID(myID, function (name) {
/*
此時myID還沒有值,因為上面的 myID = id這段代碼是需要一個時間段之後才會執行的
*/
alert(”hello:” + name);
});

比如這樣的代碼就會出錯。那麼如何解決呢?
最簡單的實現方法就是callback function的嵌套。

ServerHandler.getID(function (id) {
ServerHandler.getUserWithID(id, function (name) {
alert(”hello:” + name);
}
});
這樣我們就可以保證多個dwr方法調用的順序了。這樣貌似解決了問題。但是並不完美。
原因是當我們把JavaScript和Browser作為一個操作的平台和邏輯業務的平台(AJAX的應用程式,後面的JavaScript系列中會有提及),而不是一個簡單的展示平台的時候。這樣的回呼函數嵌套就很難控制了。
這也就是我最開始指出的需要同步非同步呼叫的一個方法。

最終我在公司的解決方案是這樣的。
寫一個訊號量的類(JavaScript的物件導向會稍後講解),當我需要執行一個方法的時候,我就申請一部分訊號量。
把需要被執行的方法放進訊號量的隊列進行等待。等前面等待的方法(如果存在)執行後在執行。
訊號量將作為一個參數被傳入執行的方法,這樣這個方法可以決定釋放這個訊號量還是繼續分發。
比如
var s = new Semaphore();
var myID = null;
s.p(function (e) { //把方法放入訊號量隊列
ServerHandler.getID(function (id) {
myID = id;
s.v(); //釋放訊號量
}
});

s.p(function (e) { //將第二個方法放到訊號量隊列,只有當前面的s.v()執行之後,這個方法才會執行。
ServerHandler.getName(myID, function (name) { //此時,可以保證myID一定有值
alert(”Hello:” + name);
s.v();
})
})

這裡只是對訊號量這個方法進行了簡單的闡述。
訊號量還支援建立自訊號量,如果建立了子訊號量,那麼父訊號量必須等帶所有的孩子都歸還了訊號量之後才可以執行他裡面的代碼。
由於代碼的著作權是公司的,所以很抱歉,現在無法給出相應的完整的訊號量的實現。
如果下一端我有時間的話,我會給出一個我實現的版本的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.