【问题标题】:Javascript/jQuery variables not giving expected valuesJavascript/jQuery 变量未给出预期值
【发布时间】:2010-01-07 14:58:56
【问题描述】:

像我之前的其他人一样,我在 Javascript 的范围内苦苦挣扎。 (那并试图阅读该死的东西)。我已经检查了关于这个问题的一些先前的线程,但我似乎无法让它们正确地应用于我的问题。 在下面的示例中,我想在数组完全填充后操作 tagsArr 数组中的值。我在填充它的函数范围之外声明了 tagsArr 变量,以便全局访问它。但该变量似乎没有我期望的范围 - tagsArr.length 在第 16 行调用输出到控制台时为 0。

            $(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);
            });
        });

【问题讨论】:

    标签: javascript jquery ajax asynchronous scope


    【解决方案1】:

    您对 getJSON 的调用是异步的。因此,在到达 console.debug 行时,对内部 getJSON 的所有调用仍然未完成。因此数组长度仍为 0。

    最终的 getJSON 调用完成后,您需要运行一些额外的代码。

            $(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); 
            }); 
        });
    

    假设照片总数不超过每页默认的 100 张,则此方法有效,否则您需要对其进行调整。

    也就是说,我认为使用 .each 来触发大量 getJSON 请求并没有多大意义。我会重构它,以便在任何时候只有一个对 getJSON 的调用是未完成的。在下一张照片的下一个 getJSON 中回调一个问题,直到所有内容都被拉出,然后执行您完成的代码。

    【讨论】:

    • 谢谢!这是一个很好的解决方案。增加totalFetched 变量(以及相关的if 子句)需要向下移动一个子句,它当前计算的是标签而不是获取的照片!
    【解决方案2】:

    $.getJSON 是异步的(ajax 中的 a)。这意味着当您到达 console.debug() 时,getJSON 仍在获取。您需要在 JSON 回调中做一些额外的工作。

    【讨论】:

    • 旁注:OP 正在在回调中工作。我认为您的意思是您需要将一些工作“移动”到 回调中。
    • 我喜欢保持我的台词简短——我没有注意到在该行的末尾有一个回调!谢谢。
    【解决方案3】:

    原因是getJSON是一个异步请求。在调用$.getJSON 之后,javascript 引擎将立即转到以下两行代码,并将输出数组的长度,届时该长度为零。直到在那之后,getJSON 请求才会收到响应,并将项目添加到数组中。

    【讨论】:

      【解决方案4】:

      getJSON 函数是异步的,所以当你调用调试函数时,数组仍然是空的,因为请求没有完成。使用 $.ajax 函数并设置 async:false 即可。

          $.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);
                     });
               } 
            }
          });
      

      【讨论】:

      • 这是一个糟糕的解决方案。
      • 应该有一个单独的$.jax函数:)
      【解决方案5】:

      这不是范围问题 - 问题在于 getJSON 是异步的,因此它在将请求发送到 flickr 后会立即继续执行。到浏览器执行 console.debug 时,请求还没有返回,您还没有完成对响应的处理(因此还没有将任何项目推送到数组中)。

      为了解决这个问题,找到所有只应在数组已满时执行的代码,并将其移至您的 getJSON 回调方法中:

      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】:

        您可能想查看this question I posted 的答案。有一些关于 javascript 范围问题的好信息。

        【讨论】:

          猜你喜欢
          • 2013-05-15
          • 2012-05-07
          • 2019-07-16
          • 2020-11-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-09-03
          • 2020-08-02
          相关资源
          最近更新 更多