可变范围。使用封闭?

时间:2011-11-17 21:37:04

标签: javascript ajax scope closures

我正试图抓住我Facebook照片的所有网址。 我首先加载带有专辑ID的“专辑”数组。 然后我遍历相册并加载带有照片网址的“图片”数组。 (我在Chrome的JS调试器中看到了这一点。)

但是当代码到达最后一个语句(“返回图片”)时,“图片”为空。

我该如何解决这个问题? 我觉得我应该使用一个闭包,但不完全确定如何做到这一点。 感谢。

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 个答案:

答案 0 :(得分:3)

你在程序上考虑你的问题。但是,只要您处理异步请求,此逻辑就会失败。我希望你最初尝试做的事情看起来像这样:

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编程的更多问题/答案。

编辑:

如果要将FB api调用的结果保存到其他代码中,可以在窗口中将返回值设置为'global'变量:

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。

答案 1 :(得分:0)

正如评论中所提到的,异步代码就像加利福尼亚酒店 - 你可以随时查看,但你永远不能离开

您是否注意到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();