当我不得不处理异步应用程序时(特别是在处理必须通过JS获取所有数据的OpenSocial代码时),我发现自己在Javascript中编写了很多意大利面条.通常的模式是这样的:
请注意,此顺序执行路径(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)
您可以看到每个函数都依赖于前一个函数,更糟糕的是,必须按特定顺序调用它才有用.当你必须在用户等待时添加诸如显示/隐藏加载屏幕和其他噱头之类的东西时会变得更糟.
你会如何解决这个问题?
一种选择可能是使用一个显示当前状态的变量,并使用一个始终是 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)