【问题标题】:How to run second Javascript function only after first function fully completes?如何仅在第一个函数完全完成后才运行第二个 Javascript 函数?
【发布时间】:2016-04-11 14:05:16
【问题描述】:

我正在使用 HTML 和 Javascript 创建一个 Facebook 游戏,并且我刚刚完成了一个排行榜,其中列出了每个玩家的姓名和排名。该表填充了从 Facebook 的游戏得分 API 返回的数据。

这是完美的工作,但我也想奖励玩家提高他们在表中的排名。

我打算这样做:

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

如果新的排名低于存储的排名,那么他们在排行榜上的排名上升了,我每提升一个位置奖励他们 100 个硬币。

例如:

玩家 A 开始游戏并排名第 5(因此“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
}

在新游戏开始时,玩家的当前排名存储在隐藏的 div 中。

当游戏结束时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 html facebook facebook-graph-api facebook-javascript-sdk


【解决方案1】:

解决这个问题的一个好方法是使用 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 :)
});

这有几个优点。您可以将任意数量的函数和操作放入.thens 链中,而无需嵌套大量回调函数。您还可以使用.catch() 访问reject() 呼叫。您应该考虑阅读 Promises 的文档,因为还有更多您应该感兴趣的功能。

如果您不想参与 Promises(它们使您的代码更简洁,因为它们是可组合,因此您可以创建非常清晰的 Promise 链),您可以查看一些其他使用回调的遮阳篷(对于这么小的用例来说还不错)。

这是一篇很棒的文章:Article: JavaScript Promises

【讨论】:

  • 在你的情况下是
  • 在你的情况下 function updateTable() { return new Promise(function(resolve, reject) { FBAPI.get(api, function (result) { resolve (response)}}} . 当调用 updateTable( ).then { compareRanks() },会像正常的序列
  • 您好@coderforlife 感谢您的回复,我正在尝试您的方法,但出现以下错误:Uncaught ReferenceError: data is not defined 你知道可能出了什么问题吗?
  • 我使用的变量是占位符,告诉你调用resolvereject时可以传递参数。您不需要将参数传递给这些函数。但如果您这样做,数据将在您的.then() 调用中传递给函数。
  • 所以你可以在不需要参数时调用first().then(second)。但是您必须记住,您不会将某些内容传递给resolve()reject()
【解决方案2】:

基本上,回调是作为参数传入另一个函数的函数。 JavaScript 可以做到这一点,因为函数是一流的对象。

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

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

updateTable(compareRanks);

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

callback(data);

【讨论】:

  • 嗨@andy 感谢您的回答,我正在尝试让它工作,但我收到了这个错误:Uncaught TypeError: callback is not a function. 你知道可能出了什么问题吗?
  • updateTablecompareRanks 方法在对象上吗?如果是这样,你可以试试updateTable(this.compareRanks)
  • 嗨@andy 我不确定你所说的“在一个对象上”是什么意思,我将排名作为内容存储在一个隐藏的 div 中(使用document.getElementById("storedrank").innerHTML),是你的对象意思是?我认为错误是在谈论“// do things”之后的callback(); 函数。
  • 嘿。把你所有的代码和JS放在一个jsfiddle里,我看看。
  • 我不知道发生了什么but here's a stripped down version of your code。请注意我如何使用compareRanks 作为回调调用updateTable,并且使用AJAX 响应调用回调(在updateTable 中)。 compareRanks(回调)然后打印出响应。希望对您有所帮助。
【解决方案3】:

最好使用 new Promise javascript 对象-

Promise 对象用于延迟和异步计算。 Promise 表示尚未完成但预计会在未来完成的操作。

new Promise(executor);

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

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

【讨论】:

    【解决方案4】:

    我认为 Aless80 的评论是您回答的关键。我不知道 Facebook API 的样子,但是每当您像这样与数据库或 Web 服务器交互时,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 基本上是建立在这个概念之上的,因此非常值得熟悉它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-07
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多