ajax和变量范围

时间:2011-08-02 19:24:52

标签: javascript jquery ajax twitter scope

我正在编写一个脚本,可以读取多个Twitter提要并将它们写入div。当我只对特定的Feed发出1个AJAX请求时,代码就可以工作,但是当我尝试遍历一个feed列表时,我什么也得不到。我很确定可变范围应该归咎于此,但我不知道如何在Javascript中解决它。

这是1-feed版本,有点简化(顺便使用jQuery):

function getTweets()
{
$.getJSON("http://api.twitter.com/1/statuses/user_timeline.json?screen_name=[my username]&count=10&include_rts=true&callback=?",
function(tweets){

    var tweetArray = new Array();

    $.each(tweets, function(i,item){
        var tweet = item.text;
        var htmlString = ...;
        tweetArray.push(htmlString);
    });

    for(var i=0;i<tweetArray.length;i++)
    {
        $("#tweet-div").append(tweetArray[i]);
    }

},"json");
}

因此,获取JSON数据,循环其内容将一些数据转换为HTML并将HTML填充到数组中,然后循环遍历该数组以将其内容填充到我的DOM中。

这是我用来尝试读取多个Feed(和失败)的代码:

function getTweets()
{
var tweetArray = new Array();
var users = new Array();
var user1 = [twitter name];
var user2 = [twitter name]; //etc for each user
users.push(user1,user2,...);

for(var n=0;n<users.length;n++)
{
    $.getJSON("http://api.twitter.com/1/statuses/user_timeline.json?screen_name="+users[n]+"&count=10&include_rts=true&callback=?",
    function(tweets){
        $.each(tweets, function(i,item){
            var tweet = item.text;
            var htmlString = ...;
            tweetArray.push(htmlString);
        });



},"json");

}//end main FOR loop

 for(var i=0;i<tweetArray.length;i++)
 {
    $("#tweet-div").append(tweetArray[i]);
 }
}

代码#2的最大区别在于我将tweetArray从.getJSON成功函数移到了它之外。似乎正在发生的事情是,当我在最后的.append()部分循环遍历tweetArray时,tweetArray中没有任何内容。

我是否正确猜测因为.getJSON成功函数是一个单独的函数,它无法从我的getTweets()函数访问局部变量tweetArray?

如果是这样,我怎样才能解决这个问题,同时仍然可以循环访问我的用户列表,就像我在#2中尝试做的那样?

如果我在这里停留的代码中有任何拼写错误,我很抱歉,但是这里的小语法错误不是问题,因为在我的网站上#1工作得很好。


更新:我意识到如果我在尝试将tweetArray数据附加到我的DOM之前将alert(tweetArray)插入到我的代码中,它甚至不需要使tweetArray成为全局变量。现在我对发生的事情更加无能为力。


更新:这是我正在使用的实际代码的复制/粘贴:

function getTweets()
{
//retrieves a JSON file from twitter.com with the information specified in the URL
//parameters. A description of parameters can be found at
//https://dev.twitter.com/docs/api/1/get/statuses/user_timeline
var tweetArray = new Array();//holds HTML-formatted tweets for everyone

var users = new Array();//holds all the user account info
var user1 = "[twitter name]";
var user2 = "[twitter name]";
var user3 = "[twitter name]";
var user4 = "[twitter name]";
var user5 = "[twitter name]";
var user6 = "[twitter name]";
var user7 = "[twitter name]";
var user8 = "[twitter name]";

users.push(user1,user2,user3,user4,user5,user6,user7,user8);

for(var n=0;n<users.length;n++)
{

    $.getJSON("http://api.twitter.com/1/statuses/user_timeline.json?screen_name="+users[n]+"&count=10&include_rts=true&callback=?",
    function(tweets){
        $.each(tweets, function(i,item){

            var tweetString;

            //the names of the various data can be found
            //in the twitter API reference pages, such as
            //https://dev.twitter.com/docs/api/1/get/statuses/user_timeline
            var tweetText = '<div class="tweet-text" id="tweet-text'+i+'" >'+item.text+'</div>';
            var userID = item.user.id_str;
            var userName = '<div class="tweet-user-name" id="tweet-user-name'+i+'" >'+item.user.name+'</div>';
            var userPic = '<img class="tweet-img" id="tweet-img'+i+'" src="'+item.user.profile_image_url +'" />';

            //formats created_at data from twitter into a nice date/time
            var tweetDate = item.created_at;
            var hourminute = tweetDate.substr(tweetDate.indexOf(":")-2,5);
            var hour = parseInt(hourminute.substr(0,2))+7;//the +7 is a time zone correction
            if (hour > 12)
            {
                hour = hour-12;
            }
            else if(hour == 0)
            {
                hour = 12;
            }
            var ampm = "AM";
            if(hour>=12)
            {
                ampm = "PM";
            }
            var minute = hourminute.substr(3,2);
            var day = tweetDate.substr(0,3)
            var dateNum = tweetDate.substr(8,2);
            var month = tweetDate.substr(4,3);
            switch(month)
            {
                case "Jan":
                month="01"
                break;
                case "Feb":
                month="02"
                break;
                case "Mar":
                month="03"
                break;
                case "Apr":
                month="04"
                break;
                case "May":
                month="05"
                break;
                case "Jun":
                month="06"
                break;
                case "Jul":
                month="07"
                break;
                case "Aug":
                month="08"
                break;
                case "Sep":
                month="09"
                break;
                case "Oct":
                month="10"
                break;
                case "Nov":
                month="11"
                break;
                case "Dec":
                month="12"
                break;
            }
            var year = tweetDate.substr(-4,4);
            var dateFormatted = '<div class="tweet-date" id="tweet-date'+i+'" >'+day+' '+month+'.'+dateNum+'.'+year+' • ' + hour +':'+ minute +' '+ ampm+'</div>';

            //reformats the date yet again so that tweets can be sorted chronologically
            var sortableDate = month+dateNum+year;

            //combines all tweet information into one string of HTML
            tweetString = '<div class="tweet" id="tweet'+i+'">'+ dateFormatted+userName+tweetText + '</div>';

            var tempArray = new Array();
            tempArray=[sortableDate,tweetString];

            //pushes formatted tweet HTML code into an array
            tweetArray.push(tempArray);
        });
    },"json");
}

//at this point in the code, the user's browser is still waiting to receive
//the JSON files from twitter, and tweetArray has no data in it. The next line
//causes the code to break for a few seconds while the data is retrieved from
//twitter before trying to insert anything into the DOM

var waitForJSON = setTimeout(function(){insertTweets(tweetArray)},2000);

}


function insertTweets(content)
{

//sort tweets in tweetArray by date instead of by author
content = content.sort();
content = content.reverse();

//change or remove the "Loading Tweets" message
if(content == "")
{
    $("#load-status").html("There was an error retreiving tweets.");
}
else
{
    $("#load-status").empty();
}

//loops through tweetArray and inserts HTML code into page
for(var i=0;i<content.length;i++)
{
    $("#tweet-box").append(content[i][1]);
}

//create patterned background effect for tweets
$(".tweet:odd").css("background-color","#f0f0f0");
$(".tweet:even").css("background-color","#dddddd");
}

2 个答案:

答案 0 :(得分:1)

  

我是否正确猜测因为.getJSON成功函数是一个单独的函数,它无法从我的getTweets()函数访问局部变量tweetArray?

完全。您可以通过将tweetArray放在函数外部来使var tweetArray = new Array(); function getTweets() { ... } 成为全局变量来解决此问题:

{{1}}

答案 1 :(得分:1)

我正朝着前一个答案的相反方向前进。你不希望tweetArray是全局的。

首先,如果你什么也没得到,那么你的代码中可能会出现语法错误,你需要找到它,因为多用户代码应该给你太多(重复的推文)而不是什么。由于这是伪代码,而不是真正的代码,我们无法真正帮助解决语法错误。因为getJSON成功函数处理程序中可能存在语法错误,所以您可能不会直接在调试器中看到语法错误。要查看它的位置,您需要在回调的开头放置一个断点,然后逐步查看它的确定位置,或者在回调中放置一个try / catch,如果抛出异常,则输出一些调试信息。 / p>

除了潜在的语法错误之外,我在第二块代码中看到的问题是你在所有成功处理程序中共享tweetArray,但是在每个成功处理程序中,你将遍历整个tweetArray并附加结果。这意味着第一个JSON调用将起作用,因为它会将初始推文收集到数组中,然后将它们全部附加。第二个JSON调用将添加到同一个数组,然后迭代整个数组并将它们全部追加。这将再次插入第一次通话的推文 - 而不是你想要的。第三个调用将再次复制之前发布的所有推文。该部分问题的解决方案是将tweetArray置于成功函数中,这样您只需收集然后从该特定JSON调用中插入推文。

为了让每条推文都附加一次,我认为你需要改变它:

function getTweets()
{
    var users = new Array();
    var user1 = [twitter name];
    var user2 = [twitter name]; //etc for each user
    users.push(user1,user2,...);

    for(var n=0;n<users.length;n++)
    {
        $.getJSON("http://api.twitter.com/1/statuses/user_timeline.json?screen_name="+users[n]+"&count=10&include_rts=true&callback=?",
        function(tweets){
            var thisUsersTweets = [];   // initialize this locally and separately for each success handler
            $.each(tweets, function(i,item){
                var tweet = item.text;
                var htmlString = ...;
                thisUsersTweets.push(htmlString);   // collect the tweets for this user only
            });

            for(var i=0;i<thisUsersTweets.length;i++)
            {
                $("#tweet-div").append(thisUsersTweets[i]);   // append just this user's tweets
            }

        },"json");  // end of getJSON call
    }               // end main "for" loop
}                   // end of getTweets()

如果您需要将整个推文列表收集到一个数组中供以后在函数中使用,那么您也可以这样做,但是由于您没有请求,我的示例不会这样做。

既然您已经发布了实际代码,并且我发现您希望在收集所有推文后对所有推文进行排序,这是在实际代码中执行此操作的方法。在此版本中,我们会计算您已启动的推文请求数量,以及收到所有回复后,我们会调用insertTweets。

我已将您的实际代码修改为此处。只有四处变化:

  1. 在函数顶层添加responsesRemaining变量
  2. 删除超时呼叫
  3. 在每次JSON调用之前增加responsesRemaining变量
  4. 在成功处理程序结束时,递减responsesRemaining变量,如果它变为零(收到所有回复),请致电insertTweets()
  5. 此版本的代码将比setTimeout版本具有以下优势:

    1. 无论推文响应时间如何,它都能正常工作。
    2. 只要它们全部可用,它就会立即插入推文,而不会等待一段时间,以便更快地显示结果。
    3. 如果获取推文的任何请求需要更长时间才能成功,此方法仍会显示他们的推文(您的推文不会)。
    4. 以下是修改后的代码:

      function getTweets()
      {
      //retrieves a JSON file from twitter.com with the information specified in the URL
      //parameters. A description of parameters can be found at
      //https://dev.twitter.com/docs/api/1/get/statuses/user_timeline
      var tweetArray = new Array();//holds HTML-formatted tweets for everyone
      var responsesRemaining = 0;
      
      var users = new Array();//holds all the user account info
      var user1 = "[twitter name]";
      var user2 = "[twitter name]";
      var user3 = "[twitter name]";
      var user4 = "[twitter name]";
      var user5 = "[twitter name]";
      var user6 = "[twitter name]";
      var user7 = "[twitter name]";
      var user8 = "[twitter name]";
      
      users.push(user1,user2,user3,user4,user5,user6,user7,user8);
      
      for(var n=0;n<users.length;n++)
      {
          ++responsesRemaining;
          $.getJSON("http://api.twitter.com/1/statuses/user_timeline.json?screen_name="+users[n]+"&count=10&include_rts=true&callback=?",
          function(tweets){
              $.each(tweets, function(i,item){
      
                  var tweetString;
      
                  //the names of the various data can be found
                  //in the twitter API reference pages, such as
                  //https://dev.twitter.com/docs/api/1/get/statuses/user_timeline
                  var tweetText = '<div class="tweet-text" id="tweet-text'+i+'" >'+item.text+'</div>';
                  var userID = item.user.id_str;
                  var userName = '<div class="tweet-user-name" id="tweet-user-name'+i+'" >'+item.user.name+'</div>';
                  var userPic = '<img class="tweet-img" id="tweet-img'+i+'" src="'+item.user.profile_image_url +'" />';
      
                  //formats created_at data from twitter into a nice date/time
                  var tweetDate = item.created_at;
                  var hourminute = tweetDate.substr(tweetDate.indexOf(":")-2,5);
                  var hour = parseInt(hourminute.substr(0,2))+7;//the +7 is a time zone correction
                  if (hour > 12)
                  {
                      hour = hour-12;
                  }
                  else if(hour == 0)
                  {
                      hour = 12;
                  }
                  var ampm = "AM";
                  if(hour>=12)
                  {
                      ampm = "PM";
                  }
                  var minute = hourminute.substr(3,2);
                  var day = tweetDate.substr(0,3)
                  var dateNum = tweetDate.substr(8,2);
                  var month = tweetDate.substr(4,3);
                  switch(month)
                  {
                      case "Jan":
                      month="01"
                      break;
                      case "Feb":
                      month="02"
                      break;
                      case "Mar":
                      month="03"
                      break;
                      case "Apr":
                      month="04"
                      break;
                      case "May":
                      month="05"
                      break;
                      case "Jun":
                      month="06"
                      break;
                      case "Jul":
                      month="07"
                      break;
                      case "Aug":
                      month="08"
                      break;
                      case "Sep":
                      month="09"
                      break;
                      case "Oct":
                      month="10"
                      break;
                      case "Nov":
                      month="11"
                      break;
                      case "Dec":
                      month="12"
                      break;
                  }
                  var year = tweetDate.substr(-4,4);
                  var dateFormatted = '<div class="tweet-date" id="tweet-date'+i+'" >'+day+' '+month+'.'+dateNum+'.'+year+' • ' + hour +':'+ minute +' '+ ampm+'</div>';
      
                  //reformats the date yet again so that tweets can be sorted chronologically
                  var sortableDate = month+dateNum+year;
      
                  //combines all tweet information into one string of HTML
                  tweetString = '<div class="tweet" id="tweet'+i+'">'+ dateFormatted+userName+tweetText + '</div>';
      
                  var tempArray = new Array();
                  tempArray=[sortableDate,tweetString];
      
                  //pushes formatted tweet HTML code into an array
                  tweetArray.push(tempArray);
              });
              --responsesRemaining;
              if (responsesRemaining <= 0) {
                  insertTweets(tweetArray);
              }
          },"json");
      }
      }
      
      
      function insertTweets(content)
      {
      
      //sort tweets in tweetArray by date instead of by author
      content = content.sort();
      content = content.reverse();
      
      //change or remove the "Loading Tweets" message
      if(content == "")
      {
          $("#load-status").html("There was an error retreiving tweets.");
      }
      else
      {
          $("#load-status").empty();
      }
      
      //loops through tweetArray and inserts HTML code into page
      for(var i=0;i<content.length;i++)
      {
          $("#tweet-box").append(content[i][1]);
      }
      
      //create patterned background effect for tweets
      $(".tweet:odd").css("background-color","#f0f0f0");
      $(".tweet:even").css("background-color","#dddddd");
      }