jQuery:如何在$ .ajax()中访问全局变量

时间:2011-08-06 15:03:03

标签: jquery

  

可能重复:
  Can't access global variable in jQuery $.get within function

这可能是一个新手问题,但在这里:我宣布了一个名为preview的全局变量。使用AJAX,我得到一个json数组并循环遍历它。对于每次迭代,我都会进行另一次AJAX调用以获取字符串并将其附加到全局变量。

但是,在第二次AJAX调用之后打印全局变量会给我“空字符串”(我肯定会从第二次AJAX调用中返回一个字符串)。

以下是代码:

var preview;
$("#some-button").click(function(e){
    e.preventDefault();
    var companies = "blahblahblah";

    $.ajax({
        url: "tracklink/getemails.php",
        type: "POST",
        data: "companies=" + companies,
        dataType: "json",
        success: function(databack) {
            if (databack) {
                for (i=0; i<databack.length; i=i+1) {
                    preview = "";
                    $("#selected-clip-list li").each(function(){
                        $.ajax({
                            url: "tracklink/cksum.php",
                            type: "POST",
                            data: "video_id=" + $(this).attr("clip_id") + "&addr=" + databack[i].email_address,
                            success: function (msg) {
                                if (msg) {
                                    preview += msg;
                                }
                                //this works
                                //console.log(preview);
                            }
                        });
                    });
                    //doesn't work
                    console.log(preview);
                }
            }
        }
    });
});

知道为什么我会得到“空字符串”吗?

非常感谢。

2 个答案:

答案 0 :(得分:5)

因为Ajax是异步。这一行:

//doesn't work
console.log(preview);

在处理响应之前执行 。这就是为什么你提供一个回调函数(success:)来处理响应的原因。

所有必须处理响应的代码必须在内部或从回调中调用。

preview无法在回调中访问(因为它可访问)无关。

更新:您可以使用Deferred objects解决此问题:

success: function(databack) {
        if (databack && databack.length > 0) {
            var deferred = $.Deferred();

            preview = "";
            for (i=0; i<databack.length; i=i+1) {
                $("#selected-clip-list li").each(function(){
                    deferred = deferred.pipe($.ajax({...}));
                });                  
            }
            deferred.then(function() {
                console.log(preview);
            });
        }
    }

这将按顺序执行Ajax请求(但不阻塞),以便以正确的顺序将响应附加到preview。但实际上我并不是100%清楚你要在preview中收集哪些数据。你确定这个嵌套for循环是否正确?

如果您不关心Ajax请求的顺序,您也可以这样做:

var deferreds = [];
for (i=0; i<databack.length; i=i+1) {
    $("#selected-clip-list li").each(function(){
       deferreds.push($.ajax({...}));
    });                  
}
$.when.apply($, deferreds).then(function() {
    console.log(preview);
});

答案 1 :(得分:0)

不幸的是,因为AJAX请求是异步的,所以它不会像你期望的那样工作。您实际上是将预览设置为空,调度一堆请求,然后打印出空变量。请求将在稍后完成并填写,但它已经打印出来。

这是你所拥有的基本重写版本,但做得更好。请记住,在ajax请求完成之前,每个函数都会返回,然后在完成所有请求后调用下一个函数。这甚至可以避免使用丑陋的全局变量。

$("#some-button").click(function(e){
  e.preventDefault();

  $.ajax({
    url: "tracklink/getemails.php",
    type: "POST",
    data: "companies=" + companies,
    dataType: "json",
    success: emailSuccess
  });

  // When the email list is returned, 
  // Look up previews for each one.
  function emailSuccess(databack) {
    if (databack) {
      for (var i=0; i<databack.length; i=i+1) {
        queryPreviews(databack[i]);
      }
    }
  }

  // Sends off ajax requests for the items
  // and calls 'previewComplete' when the preview is ready.
  function queryPreviews(data) {
    var preview = "";
    var completed = 0;

    var items = $("#selected-clip-list li");

    items.each(function(i){
      $.ajax({
        url: "tracklink/cksum.php",
        type: "POST",
        data: "video_id=" + $(this).attr("clip_id") + "&addr=" + data.email_address,
        success: function (msg) {
          completed++;
          if (msg) {
              preview += msg;
          }

          // When all of the ajax requests are done
          // Call a function to do what needs to be done with preview
          if (completed == items.length) {
            previewComplete(preview);
          }
        }
      });
    });
  }

  // Do whatever you need to do with the preview
  function previewComplete(preview) {
    console.log(preview);
  }
});