AJAX и переменная область - PullRequest
0 голосов
/ 02 августа 2011

Я пишу скрипт, который читает несколько твиттеров и записывает их в div. Код работает, когда я просто делаю 1 AJAX-запрос к определенному каналу, но когда я пытаюсь перебрать список каналов, я ничего не получаю. Я почти уверен, что здесь виновата переменная область действия, но я не знаю, как разрешить ее в Javascript.

Вот версия с 1 подачей, которая немного упрощена (кстати, с использованием 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.

Вот код, который я использую, чтобы попытаться прочитать несколько каналов (и с ошибками):

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 за ее пределы. Похоже, происходит то, что, когда я перебираю tweetArray в моей части .append () в конце, в tweetArray ничего нет.

Правильно ли я предположил, что, поскольку функция успеха .getJSON является отдельной функцией, она не имеет доступа к локальной переменной tweetArray из моей функции getTweets ()?

Если это так, как я могу это исправить, все еще будучи в состоянии перебирать мой список пользователей, как я пытаюсь сделать в # 2?

Я прошу прощения, если есть какие-либо опечатки в коде, который я застрял здесь, но незначительные ошибки синтаксиса здесь не проблема, потому что на моем сайте # 1 работает отлично.


ОБНОВЛЕНИЕ: Я понял, что если я вставляю alert (tweetArray) в свой код перед тем, как попытаться добавить данные tweetArray в мой DOM, это работает даже без необходимости превращать 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 ]

1 голос
/ 03 августа 2011

Я иду в обратном направлении от предыдущего ответа.Вы не хотите, чтобы tweetArray был глобальным.

Прежде всего, если вы ничего не получаете, то, вероятно, в вашем коде есть синтаксическая ошибка, и вам нужно ее найти, потому что многопользовательский коддолжен дать вам слишком много (дубликаты твитов), а не ничего.Так как это псевдокод, а не ваш реальный код, мы не можем точно определить, где находится синтаксическая ошибка.Поскольку синтаксическая ошибка, скорее всего, в обработчике функции успеха getJSON, вы, вероятно, не увидите синтаксическую ошибку непосредственно в отладчике.Чтобы увидеть, где она находится, вам нужно будет поставить точку останова в начале обратного вызова и пройти через нее, чтобы увидеть, где она сходит с ума, или поместить попытку / перехват внутри вашего обратного вызова и вывести некоторую отладочную информацию, если она выдает исключение.

Помимо потенциальной синтаксической ошибки, проблема, которую я вижу с вашим вторым блоком кода, заключается в том, что вы совместно используете tweetArray между всеми обработчиками успеха, но затем в каждом обработчике успеха вы выполняете итерацию по всему tweetArray идобавление результатов.Это означает, что первый вызов JSON будет работать, потому что он соберет начальные твиты в массив, а затем добавит их все.Второй вызов JSON добавит к тому же массиву, а затем итерирует по всему массиву и добавит их все.Это вставит твиты из первого звонка снова - не то, что вы хотите.Третий звонок снова дублирует все твиты, которые были до него.Решение этой части проблемы состоит в том, чтобы поместить tweetArray в функцию success, чтобы вы только собирали и затем вставляли твиты из этого конкретного вызова 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. Увеличить переменную responsesRemainingперед каждым вызовом JSON
  4. В конце обработчика успеха уменьшите значение переменной responsesRemaining и, если она упадет до нуля (все полученные ответы), вызовите insertTweets().

Эта версия кода будет иметь следующие преимущества перед вашей версией setTimeout:

  1. Она будет работать независимо от времени ответа на твиты.
  2. Она будет вставлять твиты, как тольковсе они доступны без ожидания определенного количества времени, поэтому результаты будут отображаться быстрее.
  3. Если какой-либо запрос на получение твитов займет больше времени, этот метод все равно покажет их твиты (ваш не будет).

Вот модифицированный код:

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");
}
1 голос
/ 02 августа 2011

Правильно ли я предположил, что, поскольку функция успеха .getJSON является отдельной функцией, она не имеет доступа к локальной переменной tweetArray из моей функции getTweets ()?

Точно. Вы можете исправить это, сделав tweetArray глобальной переменной, поместив ее вне функции:

var tweetArray = new Array();
function getTweets()
{
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...