Переменная сфера.Использовать закрытие? - PullRequest
2 голосов
/ 18 ноября 2011

Я пытаюсь получить все URL моих фотографий на Facebook. Сначала я загружаю массив «альбомы» с идентификаторами альбомов. Затем я перебираю альбомы и загружаю массив "pictures" с URL-адресами фотографий. (Я вижу это в JS-отладчике Chrome).

Но когда код доходит до последнего утверждения («вернуть картинки»), «картинки» становится пустым.

Как мне это исправить? Я чувствую, что должен использовать замыкание, но не совсем уверен, как лучше всего это сделать. Спасибо.

function getMyPhotos() {

        FB.api('/me/albums', function(response) {
            var data = response.data;
            var albums = [];
            var link;
            var pictures = [];


            // get selected albums id's
            $.each(data, function(key, value) {
                if ((value.name == 'Wall Photos')) { 
                        albums.push(value.id);
                }
            });
            console.log('albums');
            console.log(albums);

            // get the photos from those albums
            $.each(albums, function(key, value) {
                FB.api('/' + value + '/photos', function(resp) {
                     $.each(resp.data, function(k, val) {      
                            link = val.images[3].source;
                            pictures.push(link);
                     });
                });
            });

            console.log('pictures');
            console.log(pictures);
            return pictures;

        });
    }

Ответы [ 2 ]

3 голосов
/ 18 ноября 2011

Вы думаете о своей проблеме процедурно.Однако эта логика не работает каждый раз, когда вы работаете с асинхронными запросами.Я ожидаю, что то, что вы изначально пытались сделать, выглядело примерно так:

var pictures = getMyPhotos();
for (var i = 0; i < pictures.length; i++) {
    // do something with each picture
}

Но это не работает, поскольку значение 'pictures' на самом деле не определено (это тип возврата по умолчанию для любой функции безопределен фактический возврат - это то, что делает ваш getMyPhotos)

Вместо этого вы хотите сделать что-то вроде этого:

function getMyPhotos(callback) {
    FB.api('/me/albums', function (response) {
        // process respose data to get a list of pictures, as you have already 
        // shown in your example

        // instead of 'returning' pictures, 
        // we just call the method that should handle the result
        callback(pictures);
    });
}

// This is the function that actually does the work with your pictures
function oncePhotosReceived(pictures){
    for (var i = 0; i < pictures.length; i++) {
      // do something with each picture
    }
};

// Request the picture data, and give it oncePhotosReceived as a callback.
// This basically lets you say 'hey, once I get my data back, call this function'
getMyPhotos(oncePhotosReceived);

Я настоятельно рекомендую вам поискать SO для получения дополнительных вопросов / ответов.о обратных вызовах AJAX и асинхронном программировании JavaScript.

EDIT:

Если вы хотите, чтобы результат вызова API FB был удобным для использования другим кодом, вы можете установить возвращаемое значение на 'глобальная переменная в окне:

function getMyPhotos(callback) {
    FB.api('/me/albums', function (response) {
        // process respose data to get a list of pictures, as you have already 
        // shown in your example

        // instead of 'returning' pictures, 
        // we just call the method that should handle the result
        window.pictures = pictures;
    });
}

Теперь вы можете использовать глобальную переменную 'pictures' (или, явно используя window.pictures) где угодно.Подвох, конечно, в том, что сначала нужно вызвать getMyPhotos и дождаться завершения ответа, прежде чем они станут доступны.Нет необходимости в localStorage.

0 голосов
/ 18 ноября 2011

Как уже упоминалось в комментариях, асинхронный код похож на Hotel California - вы можете проверить в любое время, когда захотите , но никогда не сможете покинуть .

Вы заметили, как FB.api не возвращает значение

//This is NOT how it works:
var result = FB.api('me/albums')

но вместо этого получает функцию продолжения и передает ей свои результаты?

FB.api('me/albums', function(result){

Оказывается, вам нужно иметь аналогичное расположение для функции getMyPhotos:

function getMyPhotos(onPhotos){
    //fetches the photos and calls onPhotos with the 
    // result when done

    FB.api('my/pictures', function(response){

        var pictures = //yada yada

        onPhotos(pictures);
    });
}

Конечно, стиль прохождения продолжения заразителен, поэтому теперь вам нужно позвонить

getMyPhotos(function(pictures){

вместо

var pictures = getMyPhotos();
...