由于异步,数组返回未定义

时间:2016-05-23 14:45:46

标签: javascript node.js asynchronous

我正在访问API Trello,但我遇到了以下问题:

Trello访问信息,获取每个现有行的id,代码如下:

var x;  
var numberCardsByList = [];

trello.get("/1/boards/[idBoard]/lists/all", function(err, data) {
    if (err) throw err;
    console.log("Number of list: " + data.length);

    for(var i=0; i<data.length; i++){
        x = data[i];
        findNumberCards(x);
    }
});

正如你所看到的,在获得大小之后,我将所有这些队列带走,在循环内,将每一行附加到变量x中并调用一个旨在获取排队卡数的函数。卡号的代码如下:

function findNumberCards(x){
    trello.get("/1/lists/"+x.id+"/cards", function(err, dados){
        if(err) throw err;
        console.log("Name List: " + x.name + " have " + dados.length + " cards");
        numberCardsByList[x.name] = dados.length;
    });
}

在那之前可以,但是当我在Trello中搜索结束后尝试访问向量numberCardsByList时,它返回undefined:

var x;  
var numberCardsByList = [];

trello.get("/1/boards/[idBoard]/lists/all", function(err, data) {
    if (err) throw err;
    console.log("Quantidade de Filas: " + data.length);

    for(var i=0; i<data.length; i++){
        x = data[i];
        findNumberCards(x);
    }
});
console.log(numberCardsByList);

我知道这是因为异步,但无法解决。

2 个答案:

答案 0 :(得分:0)

您面临的问题以前已经解决了很多次。如果您想了解更多信息,请搜索关键字&#34; Promise&#34; 。如果您熟悉jQuery,请尝试查找:$.whenAll$.ajax().done$.ajax().always等。

如果你想自己想出一个轻量级的解决方案,这里有一个指针:

当您到达console.log(numberCardsByList)时,findNumberCards触发的请求尚未完成,Array为空。您需要确保知道所有findNumberCards请求何时完成,然后记录它们。或者,您可以在每次完成其中一个时记录

大致有两种方法:

  1. 跟踪您的未结请求,并在处理请求时调用函数。
  2. 观察您的numberCardsByList对象并在添加项目时调用函数(您不知道是否添加了异步或同步)
  3. 我建议采用第一种方法。查看此示例代码和注释:

    &#13;
    &#13;
    var numberCardsByList = {};
    
    // This array will store the url for every open request
    var openRequests = [];
    
    var removeRequest = function(url) {
      var index = openRequests.indexOf(url);
      if (index === -1) return;
    
      // Remove url from array
      openRequests = openRequests
        .slice(0, index)
        .concat(openRequests
          .slice(index + 1));
    };
    
    // This will be called whenever one request completes
    var onComplete = function(url) {
      removeRequest(url);
      
      // When all have completed, we can call our callback
      if (openRequests.length === 0) {
        onAllComplete();
      }
    
    });
    
    // This will be called when there are no open requests left
    var onAllComplete = function(data) {
      console.log(numberCardsByList);
    }
    
    
    trello.get("/1/boards/[idBoard]/lists/all", function(err, data) {
      if (err) throw err;
      console.log("Number of list: " + data.length);
    
      for (var i = 0; i < data.length; i++) {
        x = data[i];
        findNumberCards(x);
      }
    });
    
    
    function findNumberCards(x) {
      var url = "/1/lists/" + x.id + "/cards";
      
      // Before we make the request, we register it:
      openRequests.push(url);
    
      trello.get(url, function(err, dados) {
        numberCardsByList[x.name] = dados.length;
        
        // When it is completed, we call onComplete
        onComplete(url);
      });
    };
    &#13;
    &#13;
    &#13;

    请注意,此onAllComplete并非100%安全:如果请求在下一个请求启动之前完成,则可能会多次调用它。

    <强>结论

    如果可以,我会使用库来处理承诺。如果你想尝试自己构建一些东西,你可以尝试跟踪请求并在它们全部完成后执行回调。

答案 1 :(得分:0)

请记住,我的上述代码很可能不适合您,因为我不知道您的代码中发生了什么,所以这是一个示例/解释如何处理您的问题。

由于您不熟悉异步操作,我会假设您没有先前的承诺知识,因此会给您一个不太理想的解决方案 - 但是承诺会更好,您应该彻底学习它们。

您需要在异步代码的结果中执行序列过程。

首先,您将为第二个操作创建一个函数,例如:

function numberCardsByList (param1,param2){.....}

然后,您将更改fineNumberCards以接受回调:

function findNumberCards(x, callback){
    trello.get("/1/lists/"+x.id+"/cards", function(err, dados){
        if(err) throw err;
        console.log("Name List: " + x.name + " have " + dados.length + " cards");
        numberCardsByList[x.name] = dados.length;
    });

    // pass in any params you need.
    callback();
}

然后您将新创建的函数numberCardsByList传递给findNumberCards或任何您想要的地方。     trello.get(“/ 1 / boards / [idBoard] / lists / all”,function(err,data){         if(err)throw err;         console.log(“列表数:”+ data.length);

    for(var i=0; i<data.length; i++){
        x = data[i];
        // and here we are calling findNumberCards and passing in the callback..
        findNumberCards(x, numberCardsByList);
    }
});

通常你将如何处理异步操作,你将为下一个要执行的操作传递一个回调函数。

<强>更新

这里有一个例子,说明如何用另一个场景来完成这一点,只是为了证明这一点。

我们从获取用户开始

service.getUser(userName, function(err,user){
  if(user) {
    // we get user picture passing getPictureSize as callback
    getUserPicture(user.picture, getPictureSize)
  }
})

我们得到pictureURL

function getUserPicture(picName, cb){
  service.getPictureURL(picName, function(err, pictureURL){
    if(pictureURL) {
      // we then call the callback - the next async operation we want.
      cb(pictureURL);
    }
  });
}

我们得到图片大小 - 这是最后一次操作

function getPictureSize(pictureURL){
  service.getPictureSize(pictureURL, function(err, pictureSize){
    $('.picName').attr('src', picName);
    $('.picName').width(pictureSize.width);
    $('.picName').height(pictureSize.height);
  });

}

我希望稍微澄清一下。