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

时间:2016-04-11 14:05:17

标签: javascript html facebook facebook-graph-api facebook-javascript-sdk

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

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

我打算这样做:

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

如果新排名的数字低于存储的排名,那么他们就会向排行榜上移,我会奖励每个排名上升的100个硬币。

例如:

玩家A开始游戏并排名第5(所以“5”存储在隐藏的div中)。 当玩家A完成游戏时,排行榜会更新,玩家A现在排名第2(因此玩家已经跳了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();完全完成之前运行。

我非常感谢你解决这个问题的任何帮助,谢谢你提前!

4 个答案:

答案 0 :(得分:3)

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

$body = new stdClass();
$body->comment = "Check out https://github.com/faisalahsan";
$body->content = new stdClass();
$body->content->title = "Test ABCasdfadsf";
$body->content->description = "My Open Source Contribution";
$body->content->{'submitted-url'} = "https://github.com/faisalahsan";
$body->content->{'submitted-image-url'} = "https://avatars0.githubusercontent.com/u/8427383?v=3&s=460";
$body->visibility = new stdClass();
$body->visibility->code = "anyone";

$body_json = json_encode($body, true);

$client = new GuzzleHttp\Client(['base_uri' => 'https://api.linkedin.com']);
$access_token =  'AQWJ0bPoW9VpPrEYWvywLk2cx1fhwysjaadsfjja#fsExHBIJvTUGa_t_3FvaqZPnrsMACC-JyPvpL2GBANlOMLUBSK8OEyfUl9_VLoxVe4ACBePysj-_WHv1-PP-Q-xas2owrngUtlq9P7Z2o95XUiO-Xhd9y0bm36DX9JXyxW-3jV2uBwP9pLJDC_FRZQ2JiCE';

$req = $client->request('POST', '/v1/people/~/shares?format=json', [
        'headers'           => ["Authorization" => "Bearer " . $access_token,
                    "Content-Type" => "application/json",
                            "x-li-format"=>"json"],
        'client_id'     => '77gasdfkjo22v44',
                'client_secret' => 'iXadQ123askdfzPbz7Js',
        'body'      => $body_json
    ]);
var_dump($req);
die;

这带来了一些优点。您可以将任意数量的函数和操作放入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访问reject()来电。你应该阅读Promises的文档,因为还有更多的功能应该对你有用。

如果您不想参与Promises(它们使您的代码更加清晰,因为它们可组合,因此您可以创建非常清晰的承诺链),您可以查看一些其他使用Callbacks的芒果(对于这么小的用例来说并不坏)。

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

答案 1 :(得分:2)

回调基本上是一个函数作为参数传递给另一个函数。 JavaScript可以这样做,因为函数是第一类对象。

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

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

updateTable(compareRanks);

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

callback(data);

答案 2 :(得分:1)

最好使用javascript- {/ p>的new Promise对象

  

Promise对象用于延迟和异步计算。承诺代表了一项尚未完成的行动,但预计将来会有所作为。

     

new Promise(executor);

     

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

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

答案 3 :(得分:1)

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基本上都是基于这个概念,所以非常值得熟悉它们。