阵列群体在添加的功能之外不存在?

时间:2018-04-22 23:34:58

标签: javascript arrays for-loop app-lab

我对JavaScript很陌生,而且我遇到了一个无法找到解决方案的问题。我正在为我的APCS最终项目开发一款游戏,并且我试图为它添加一个排行榜。为了找到顶级玩家,我将所有高分放在一个数组中,将其从最大值排序到最小值,然后搜索5个与数组中前5个数字匹配的用户名。我使用AppLab创建它,AppLab有一个内置的数据库功能,所以&#34; readRecords的用途是什么。我的问题是,当我使用for循环填充数组时,即使数组变量是在函数外部创建的,人们也不会在函数外部存在,这里的代码是...... < / p>

function leaderGrabEasy() {
  var leaderScores = [];
  var leaders = [];
  readRecords("userData",{},function(records) {
    for (var i = 0; i < records.length; i++) {
      leaderScores.push(records[i].E_highscore);
    }
    leaderScores.sort(function(a, b){return b-a});
  });
  readRecords("userData",{E_highscore:leaderScores[0]},function(records) {
    for (var i = 0; i < records.length; i++) {
      leaders.push(records[i].username);
    }
    console.log(leaders);
  });
}

当我尝试读取数据库列时出现问题&#34; E_highscores&#34;对于&#34; leaderScores [0]&#34;

中的任何内容
readRecords("userData",{E_highscore:leaderScores[0]},function(records) {

但是因为数组在第一个函数之外是空的,所以数组中的那个点是空的。在此先感谢您的帮助!

-Indoors

2 个答案:

答案 0 :(得分:0)

readRecords是一个异步函数,对吗?

问题是你有竞争条件。这意味着代码需要以非常特定的顺序执行才能工作,但您目前无法控制该命令。

得分被推送到传递给leaderScore的回调中的readRecords。但是,在下一行(调用readRecords后)之后,您尝试再次调用readRecords,其中一个值填充 回调到第一个{{ 1}}。

基本上,您的代码按此顺序执行:

readRecords

事实上,readRecords("userData",{},callback1) readRecords("userData",{E_highscore:leaderScores[0]},callback2) callback1() callback2() 之前无法保证callback1

有许多工具可以解决这个异步排序问题,比如Promises等。我将选择最简单的选项,然后重新排列代码。这将创建嵌套的回调,但是现在,它可以工作,并且(希望)可以帮助您看到这个原则。

callback2

现在第二个function leaderGrabEasy() { var leaderScores = []; var leaders = []; readRecords("userData",{},function(records) { for (var i = 0; i < records.length; i++) { leaderScores.push(records[i].E_highscore); } leaderScores.sort(function(a, b){return b-a}); readRecords("userData",{E_highscore:leaderScores[0]},function(records) { for (var i = 0; i < records.length; i++) { leaders.push(records[i].username); } console.log(leaders); }); }); } 只会在填充数组之后发生,而不是之前的任何时间。

这确实打开了可重用性的其他问题。如果你想稍后做更复杂的事情,或者添加更多的回调,甚至可能是一个循环,该怎么办?嗯,这将是你的哈哈。但是如果你记住我们在这里讨论的原则,你肯定可以成功地做到这一点:任何异步回调都可以在任何时间进行调用,所以总是正确地考虑你的代码。

问自己一个问题:如果在1毫秒,500毫秒和1分钟内内联(按照写入的顺序)同步调用此回调,我的代码是否可以工作?如果是这样,那么它在逻辑上是合理的。

答案 1 :(得分:0)

将函数转换为promise函数而不是嵌套回调可能会更好。代码现在可能很容易维护,但是当你写的越来越多时,后面的代码就越难解开。

//readRecords as a promise returning function
function readAsPromise(str,obj){
  return new Promise(
    function (resolve,reject){
      readRecords(
        str,
        obj,
        function(records,error) {//this readRecords cannot fail?
          if(error){
            reject(error);return;
          }
          resolve(records);
        }
      );
    }
  );
}

function leaderGrabEasy() {
  return Promise.all([
    readRecords("userData",{}),
    readRecords("userData",{E_highscore:leaderScores[0]})
  ])
  .then(
    function(results){
      return {
        leaderScores:results[0]
          .map(function(leader){return leader.E_highscore;})
          .sort(function(a, b){return b-a}),
        leaders:results[1]
          .map(function(leader){return leader.username})
      }
    }
  )
}

//use the function:
leaderGrabEasy()
.then(
  function(result){
    console.log("result:",result);
  }
)
.catch(
  function(error){
    console.log("there was an error:",error);
  }
)

//arrow function syntax:
leaderGrabEasy()
.then(result=>console.log("result:",result))
.catch(error=>console.log("there was an error:",error));

在现代语法中,它看起来像这样:

//readRecords as a promise returning function
const readAsPromise = (str,obj) =>
  new Promise(
    function (resolve,reject){
      readRecords(
        str,
        obj,
        function(records,error) {//this readRecords cannot fail?
          if(error){
            reject(error);return;
          }
          resolve(records);
        }
      );
    }
  );

const leaderGrabEasy = () =>
  Promise.all([
    readRecords("userData",{}),
    readRecords("userData",{E_highscore:leaderScores[0]})
  ])
  .then(
    ([score,name])=>({
      leaderScores:score.map(leader=>leader.E_highscore).sort((a, b)=>b-a),
      leaders:name.map(name=>nae.username)
    })
  )

//use the function:
leaderGrabEasy()
.then(result=>console.log("result:",result))
.catch(error=>console.log("there was an error:",error));