Javascript/jQuery variables not giving expected va

2019-07-18 14:11发布

Like others before me I'm struggling with scope in Javascript. (That and trying to read the darn stuff). I have checked some of the previous threads on this question but I cant seem to get them to apply correctly to my issuue. In the example below, I want to manipulate the values in the tagsArr array, once the array has been fully populated. I declared the tagsArr variable outside the scope of the function in which it is populated in order to access it globally. But the variable doesn't seem to have the scope I expect - tagsArr.length is 0 at the point where I call output it to console on line 16.

            $(function(){
            var apiKey = [myapikey];
            var tags = '';
            var tagsArr = new Array();
            $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&api_key=' + apiKey + '&user_id=46206266@N05&extras=date_taken,tags&format=json&jsoncallback=?', function(data){
                $.each(data.photos.photo, function(i, item) {
                    var photoID = item.id;
                    $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?', function(data){
                        if (data.photo.tags.tag != '') {
                            $.each(data.photo.tags.tag, function(j, item) {
                                tagsArr.push(item.raw);
                            });
                        }                            
                    });
                    tags = tagsArr.join('<br />');
                    console.debug(tagsArr.length);
                });
                $('#total-dragged').append(data.photos.total);
                $('#types-dragged').append(tags);
            });
        });

6条回答
Emotional °昔
2楼-- · 2019-07-18 14:22

You may want to check the answer to this question I posted. There is some good information on scope issues in javascript.

查看更多
劳资没心,怎么记你
3楼-- · 2019-07-18 14:25

Your calls to getJSON are asynchronous. Hence all the calls to the inner getJSON will still be outstanding by the time the console.debug line is reached. Hence the array length is still 0.

You need to run some extra code once the final getJSON call has completed.

        $(function(){ 
        var apiKey = [myapikey]; 
        var tags = ''; 
        var tagsArr = new Array(); 
        $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.people.getPublicPhotos&api_key=' + apiKey + '&user_id=46206266@N05&extras=date_taken,tags&format=json&jsoncallback=?', function(data){

            var totalExpected = data.photos.total;
            var totalFetched = 0;

            $.each(data.photos.photo, function(i, item) { 
                var photoID = item.id;

                $.getJSON('http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?', function(data){ 
                    if (data.photo.tags.tag != '') { 
                        $.each(data.photo.tags.tag, function(j, item) { 
                            tagsArr.push(item.raw);
                            totalFetched += 1;
                            if (totalFetched == totalExpected)
                              fetchComplete();
                        }); 
                    }                             
                });
                function fetchComplete()
                { 
                    tags = tagsArr.join('<br />'); 
                    console.debug(tagsArr.length); 
                }
            }); 
            $('#total-dragged').append(data.photos.total); 
            $('#types-dragged').append(tags); 
        }); 
    });

This works assuming the total number of photos doesn't excede the default 100 per page, other wise you would need to tweak it.

That said I don't think using .each to fire off loads of getJSON requests makes a great deal of sense. I would refactor it so that only one call to getJSON is outstanding at any one time. Have the callback of one issue the next getJSON for the next photo until all have been pulled then do your completed code.

查看更多
走好不送
4楼-- · 2019-07-18 14:33

$.getJSON is asynchronous (the a in ajax). That means that by the time you get to console.debug(), getJSON is still getting. You'll need to do some extra work in the JSON callback.

查看更多
ら.Afraid
5楼-- · 2019-07-18 14:33

This isn't a scope issue - the problem is that getJSON is asynchronous, so it continues executing immediately after sending the request to flickr. By the time the browser executes console.debug the request hasn't returned and you haven't finished handling the response (and therefore haven't pushed any items into the array yet).

To solve this, find all the code that should only be executed when the array is full and move it into your getJSON callback method:

if (data.photo.tags.tag != '') {
    $.each(data.photo.tags.tag, function(j, item) {
        tagsArr.push(item.raw);
    });
    tags = tagsArr.join('<br />');
    console.debug(tagsArr.length);
    $('#total-dragged').append(data.photos.total);
    $('#types-dragged').append(tags);
}
查看更多
我命由我不由天
6楼-- · 2019-07-18 14:40

The reason for this is that getJSON is an asynchronous request. after the call to $.getJSON, the javascript engine will move immediately on to the following two lines of code, and will output the length of your array, which is by then, zero-length. Not until after that does the getJSON request receive a response, and add items to the array.

查看更多
做自己的国王
7楼-- · 2019-07-18 14:44

The getJSON function is asynchronous, so when you call the debug function the array is still empty because the requests are not completed. Use the $.ajax function and set async:false and it will work.

    $.ajax({
      type: "GET",
      url: 'http://api.flickr.com/services/rest/?&method=flickr.photos.getInfo&api_key=' + apiKey + '&photo_id=' + photoID + '&format=json&jsoncallback=?',
      dataType: "json",
      async:false,
      success:function(data){
         if (data.photo.tags.tag != '') {
               $.each(data.photo.tags.tag, function(j, item) {
                   tagsArr.push(item.raw);
               });
         } 
      }
    });
查看更多
登录 后发表回答