如何在第一个函数完全完成后才运行第二个Javascript函数



我正在使用HTML和Javascript创建一个Facebook游戏,我刚刚完成了排行榜的构建,其中列出了每个玩家的姓名和排名。此表包含从Facebook的游戏评分API返回的数据。

这非常有效,但我也想奖励那些在积分榜上排名提高的球员。

我计划这样做:

  • 当游戏加载时,我运行一个名为updateTable();的函数用玩家的分数和排名填充排行榜从对Facebook数据库的API调用接收
  • 当玩家开始玩游戏时,我会将他们等级的副本存储在一个单独的隐藏div中
  • 当游戏结束时,如果玩家获得了新的高分,那么它被输入到数据库中。发生这种情况后,我就跑再次updateTable();更新排行榜
  • 然后我运行一个名为compareRanks();的函数,它将玩家的新等级与我存储在隐藏分区中的等级

如果新的排名比存储的排名低,那么他们已经在排行榜上排名上升,我会奖励他们每上升一个位置100枚硬币。

例如:

玩家A开始游戏,排名第五(因此"5"存储在一个隐藏的div中)。当玩家A完成游戏时,排行榜会更新,玩家A现在排名第二(因此玩家跳了3位)。

为了计算奖励应该是多少,我想从第二个变量中减去第一个变量(5-2=3),玩家A超过了其他3名玩家,所以他们的奖励将是3 x 100金币。

我遇到的问题是,当我运行compareRanks();时,新的等级一直显示为与存储的等级相同的数字,尽管我知道玩家已经提高了他们的等级。

我敢肯定这是由于updateTable();在与数据库完全交互之前就已经获取了新的排名。我已经通过分离功能进行了测试,通过点击按钮使compareRanks();运行,当我这样做时,我完成了一个游戏,提高了我的排名,在updateTable();运行后等待几秒钟,然后点击按钮,两个排名显示不同,这是正确的。所以我认为compareRanks();只需要等待updateTable();完全完成即可运行。

这就是我的功能布局:

updateTable(){
//code here interacts with the database/makes a call using Facebook's API, 
//and populates the leaderboard table with the returned data
}

在新游戏开始时,玩家的当前等级存储在隐藏的分区中。

游戏结束后,再次运行updateTable();,然后运行compareRanks();:

compareRanks(){
//code here grabs the stored rank from the hidden div
//code here grabs the newly updated rank and compares the two.
}

我读过关于使用回调的答案,但我无法让它们发挥作用。我试过做这样的事情:

updateTable(){
{
//code here interacts with the database/makes a call using Facebook's API,
//and populates the leaderboard table with the returned data
}
compareRanks();
};

但是当compareRanks();运行时,新的秩仍然显示为与旧秩相同。updateTable();在运行时正确地更改了排行榜上的排名,所以我认为compareRanks();只是在updateTable();完全完成之前运行的。

如果能帮我解决这个问题,我将不胜感激,提前谢谢!

实现这一点的一个好方法是使用Javascript Promises。它们允许您在不嵌套多个回调函数的情况下执行异步操作。

function first (parameter){
  return new Promise(function(resolve,reject){
   //Do async stuff, maybe some ajax
   //When async stuff is finished:
    resolve(async_data);
   //Or when something went wrong:
    reject(error);
 }
}
function second(parameter){
  return new Promise(function(resolve,reject){
   //Do async stuff, maybe some ajax
   //When async stuff is finished:
    resolve(async_data);
   //Or when something went wrong:
    reject(error);
 }
}
//You can then use:
first(data).then(second(async_data)).then(function(async_data){
    //Here would be the point where both functions finished after eachother!
}).catch(function(error){
    //Hey, one of my promises was rejected! Maybe I should handle that error :)
});

这有几个优点。您可以将任意多的函数和操作放入.then的链中,而无需嵌套大量的回调函数。您也可以使用.catch()访问reject()调用。你应该仔细阅读Promises的文档,因为还有更多的功能对你来说应该很有趣。

如果你不想参与Promises(它们让你的代码更干净,因为它们是可组合的,所以你可以创建非常清晰的Promises链),你可以研究一些其他可以使用回调的awnser(对于这样一个小用例来说没那么糟糕)。

这里有一篇关于它的好文章:文章:JavaScript Promises

基本上回调是作为参数传递给另一个函数的函数。JavaScript之所以能够做到这一点,是因为函数是一流的对象。

现在,因为updateTable将调用db/FB API,所以您需要在该操作的回调中调用回调。我不知道该操作的正确语法,所以我的示例使用伪代码。

function updateTable(callback) {
   FBAPI.get(something, function (data) {
     // do things
     callback();
   });
}
updateTable(compareRanks);

注意,如果compareRanks需要访问API中的数据,您也可以将数据传递给回调:

callback(data);

最好使用javascript的new Promise对象-

Promise对象用于延迟和异步计算。Promise代表一项尚未完成的操作,但有望在未来完成。

new Promise(executor);

new Promise(function(resolve, reject) { ... });

查看此链接以获取更多帮助-https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise

我认为Aless80的评论是你答案的关键。我不知道Facebook API是什么样子的,但每当你像这样与数据库或网络服务器交互时,API调用通常会有一个回调,你可以在其中处理服务器可能返回给你的任何内容。

例如,我正在处理的一个简单的web服务器处理通过浏览器的AJAX调用发送的请求。我使用Jquery来实现这一点,但结构应该大致相同。

var dataObject = {};
var dataID = "1234";
$.ajax({
  type: "GET", // basic http get request
  url: "http://www.mywebserver.com/get-data/" + dataID,
  crossDomain: true 
}).done(function(response){
  // this function runs after the webserver has received our GET request and handled it
  // response contains the data we got back from mywebserver
  dataObject = response;
});
DoSomething(dataObject);

这里发生的情况是,"DoSomething()"将在dataObject包含数据库返回的任何数据之前激发!因此,如果我们想对返回的数据进行处理,我们应该在ajax请求的"回调"中调用函数,如下所示:

var dataObject = {};
var dataID = "1234";
$.ajax({
  type: "GET", // basic http get request
  url: "http://www.mywebserver.com/get-data/" + dataID,
  crossDomain: true 
}).done(function(response){
  //dataObject = response;
  //DoSomething(dataObject);
  DoSomething(response);
});

这个例子中注释掉的东西是为了清楚起见,当然,我们希望避免不必要地传递变量:)

我还强烈建议研究JavaScript回调。它们一开始很难理解,但Node.js基本上是建立在这个概念的基础上的,因此非常值得熟悉它们。

最新更新