如何在Javascript中避免意大利面条代码

Fed*_*les 13 javascript ajax

当我不得不处理异步应用程序时(特别是在处理必须通过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();
}
Run Code Online (Sandbox Code Playgroud)

您可以看到每个函数都依赖于前一个函数,更糟糕的是,必须按特定顺序调用它才有用.当你必须在用户等待时添加诸如显示/隐藏加载屏幕和其他噱头之类的东西时会变得更糟.

你会如何解决这个问题?

Jac*_*son 4

一种选择可能是使用一个显示当前状态的变量,并使用一个始终是 AJAX 回调函数的“控制器”函数。根据当前状态,控制器函数将调用行中的下一个函数。为了简化控制器函数,我可能会存储要在 Javascript 对象中调用的函数序列,因此控制器函数所做的只是查找并传递到序列中的下一个函数。通过使用一个始终作为函数参数(并包含早期 AJAX 调用返回的所有数据)的 Javascript 对象,可以简化此方法。

例子:

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 
}
Run Code Online (Sandbox Code Playgroud)