2009-10-15 64 views
13
麪條代碼

我發現自己寫了很多在Javascript意大利麪條的時候我必須處理異步 應用(特別是與所有的數據必須通過JS獲得 OpenSocial的代碼打交道時) 。通常的模式是這樣的:如何避免在Javascript

  1. 用戶第一次登錄到應用程序,獲取他的數據。
  2. 對他的數據做A(例如通過向服務器發送請求來獲得他的朋友)。
  3. 對此數據執行B操作(例如,將他的朋友發送給服務器進行一些處理)。
  4. 對他的數據做C(例如,檢查服務器響應是否有效,以便我們可以做其他事情)。

請注意,此順序執行路徑(1 => 2 => 3 => 4)不適合異步。性質 Ajax,所以用戶最終等待很長時間,代碼變成一團糟,因爲每個步驟 取決於以前的。

的代碼示例:

gadgets.util.registerOnLoadHandler(setupUser()) 
... 
function setupUser() { 
    var req = [get data and setup request] 
    req.send(some_url, some_data, function(response) { getFriendsFor(response.user) }); 
} 

function getFriendsFor(user) { 
    var friends = [get friends from user] 
    var req = [setup request] 
    req.send(some_other_url, some_other_data, function(response { validateFriendsResponse(response.friends) }); 
} 

function validateFriendsResponse(friends) { 
    if (friends.valid()) 
    ... 
    loadCanvas(); 
} 

你可以看到每個函數依賴於前一個,更糟糕的是,它在 被稱爲一個特定的順序是有用的。當用戶在等待時添加諸如顯示/隱藏加載 屏幕和其他噱頭之類的東西時,情況會變得更糟。

你會如何去修復呢?

+6

煮它,直到它是人類 – 2009-10-15 15:41:55

+2

您的主要擔心似乎是用戶最終等待很長時間才能完成所有這些。爲什麼不在每次請求返回後向用戶提供一些反饋,以便他們知道發生了什麼。它可以像3階段進度條一樣簡單,或者告訴用戶發生了什麼。 (你甚至可以用「reticulating splines」消息來形容meme apeal。) – 2009-10-15 16:18:26

+0

Sam:我現在用一個可愛的機器人拍着手臂顯示加載屏幕,但是代碼也讓我擔心,因爲我知道我會有一些在幾個月內閱讀它的問題。 – 2009-10-16 16:06:29

回答

4

一種選擇可能是有一個變量,顯示當前狀態,並有一個「控制器」功能,始終是AJAX回調函數。根據當前狀態,控制器功能將調用下一個功能。爲了簡化控制器功能,我可能會存儲函數序列以調用Javascript對象,因此所有控制器函數都是查找並傳遞給序列中的下一個函數。這種方法可能具有一個JavaScript對象始終是參數的功能(幷包含所有,是由早期的AJAX調用返回的數據來促進

例:

var user = {}; 
var currentState = 1; 

var someFunction = function(user) {//stuff here that adds data to user via AJAX, advances currentState, and calls controllerFunction as callback}; 
var someOtherFunction = function(user) {//stuff here that does other things to user, advances currentState, and calls controllerFunction as callback} 

var functionSequence = {1:someFunction, 2:someOtherFunction} 

var controllerFunction = function() { 
    //retrieve function from functionSequence based on current state, and call it with user as parameter 
} 
1

構建您的JavaScript客戶端與MVC架構

+1

javascriptMVC - 猜他們應該得到他們的鏈接在IE8上工作! – ScottE 2009-10-15 16:00:00

+1

我會將Backbone(http://documentcloud.github.com/backbone/)和Spine(http://spinejs.com/)添加爲輕量級客戶端MVC框架。 – jbandi 2011-12-04 13:40:30

1

處理顯示,隱藏和狀態特徵的代碼應該被提取到函數中。然後,爲了避免「spagheiness」,一種解決方案是使用匿名函數內聯。

function setupUser() { 
    var req = [get data and setup request] 
    req.send(some_url, some_data, function(response) { 
    var friends = [get friends from user] 
    var req = [setup request] 
    req.send(some_other_url, some_other_data, function(response {   
     if (friends.valid()) 
     ... 
     loadCanvas(); 
    }); 
    }); 
} 
+0

這就是我剛開始時所做的,但遺憾的是OpenSocial JS API太冗長了。你可以在這裏看到你的例子中的第2-4行在OS中的樣子:http://gist.github.com/211062。有些代碼可以在函數中被抽象出來,但它仍然會有像瘋子一樣跳躍的問題。 – 2009-10-15 16:20:43

0

如果你希望你的函數能夠獨立運行的,裝備異步那些與通用的回調,而不是調用行中的「下一個」功能。然後,正如JacobM所說,設立一個「控制器」,可以按順序調用它們。我已經修改了你的下面的代碼示例演示(注意,這還沒有經過測試):

gadgets.util.registerOnLoadHandler(userSetupController()) 
... 
function setupUser(callback) { 
    var req = [get data and setup request] 
    req.send(some_url, some_data, function(response) { callback(response.user) }); 
} 

function getFriendsFor(user,callback) { 
    var friends = [get friends from user] 
    var req = [setup request] 
    req.send(some_other_url, some_other_data, function(response { callback(response.friends) }); 
} 

function validateFriendsResponse(friends) { 
    if (friends.valid()) 
    return true; 
    else 
    return false; 
} 

function userSetupController() { 
    setupUser(function(user){ 
     getFriendsFor(user,function(friends){ 
      if (validateFriendsResponse(friends)) { 
       loadCanvas(); 
      } else { 
       // don't load the canvas? 
      } 
     }); 
    }); 
} 

創建回調得到,如果你不熟悉這些有點複雜 - 這裏有一個體面的解釋:http://pixelpushing.net/2009/04/anonymous-function-callbacks/。如果你想變得更復雜(同樣,正如JacobM所建議的那樣),你可以編寫一些自動處理的代碼 - 給它一個函數列表,並按順序執行它們,傳遞迴調數據。方便,但可能會爲你的需要矯枉過正。

2

可以控制這種事情就像Observer pattern麪條。一些JavaScript框架具有此功能的即用型實現,例如Dojo's發佈/訂閱功能。問題的

1

部分原因是,你在想這是有三個往返所需要的服務器的四步過程。如果你真的認爲這是一個單一的工作流程,並且用戶最有可能做的事情,那麼最好的加速就是在第一次互動中收集儘可能多的信息以減少往返次數。這可能包括允許用戶選中一個表示她想要遵循此路徑的框,因此您不必在步驟之間返回給用戶,或者允許她輸入對朋友名稱的猜測,以便處理第一次,或第一次預加載名單。

如果這只是用戶可能遵循的許多路徑之一,那麼您已經勾勒出代碼的方式效果最佳;多次往返都是必需的,因爲在每次交互中,你都會發現用戶想要什麼,而不同的答案會讓你朝不同的方向發展。這是當你鬆散耦合的代碼風格真正閃耀的時候。由於用戶的行爲正在推動活動,因此每個步驟看起來都與之前的行爲沒有關聯。

所以,真正的問題是用戶是否在決定你的代碼去的方向開始有一個選擇。如果不是,那麼你想優化你知道(或強烈預測)交互行爲的路徑。另一方面,如果用戶交互驅動流程,那麼將步驟分離並對每個交互作出反應是正確的,但您會期望更多不同的可能性。