在运行代码之前等待jQuery的$.get函数完成

3
在下面的代码中,return语句在调用$.get()完成之前被执行。我该如何更改这个问题?
var aft = {};

aft.getToken = function (url) {

    var theToken;

    //Get the token value
    $.get(url, function (data) {

        theToken = $(data).find('input[name=__RequestVerificationToken]').val();

    }, "html");

    return theToken;

};

4
欢迎来到异步编程的精彩世界!你不能这样做。 - SLaks
3个回答

4
jQuery支持此功能,只需将选项async设置为false,函数调用将变为同步,而不是异步。但我建议您保持请求异步,请参见本文末尾的"推荐解决方案"。

async(布尔值)默认值:true

默认情况下,所有请求都是异步发送的(即默认设置为true)。如果需要同步请求,请将此选项设置为false。跨域请求和dataType: "jsonp"请求不支持同步操作。

请注意,同步请求可能会暂时锁定浏览器,在请求处于活动状态时禁用任何操作。


但我正在使用$.get,那似乎是针对$.ajax特定的?

是的,但在幕后,它们完全相同。

jQuery.get ():

This is a shorthand Ajax function, which is equivalent to:

$.ajax({
  url: url,
  data: data,
  success: success,
  dataType: dataType
});

示例实现

aft.getToken = function (url) {
  var theToken;

  $.ajax({
    url: url,
    dataType: 'html'
    success: function (data) {
      theToken = $(data).find('input[name=__RequestVerificationToken]').val();
    },
    dataType: dataType
  });

  return theToken;
}

推荐解决方案

正如jQuery文档中先前提到的评论所述,异步请求通常不建议使用,往往会带来更多的麻烦。

相反,您应该尝试使用回调或类似的功能来实现所需的功能。

回调是传递给其他函数以处理某些事件(例如数据检索成功)的函数。就像您在自己的代码片段中向$.get传递回调一样。

让您的函数aft.getToken接受一个名为callback的第二个参数,它应该是一个函数引用。然后,在数据检索和“解析”完成时,使用通过ajax请求回复的令牌作为参数调用此函数。

aft.getToken = function (url, callback) {
  var dst_object = this;

  $.get (url, function (data) {
    dst_object.stored_token = $(data).find (
      'input[name=__RequestVerificationToken]'
    ).val ();

    callback (dst_object.stored_token);
  }, "html");
};

...

aft.getToken ('/path/to/file.html', function (token) {
  console.log ("Got token: " + token);
});

...

console.log (aft.stored_token);

这应该是一个最后的解决方案,只有在回调函数或代码重组绝对行不通时才实施。 - jwheron
1
不要使用同步请求。相反,学习如何使用事件模型编程,这是浏览器中JavaScript的基础。 - Matti Virkkunen
2
@MattiVirkkunen,也许你可以提供一个有用的答案来解决OP的问题,并符合您的标准,而不是评论每个人关于OP不应该做什么的答案。 - ThinkingStiff
@ThinkingStiff: Adam Rackis已经做过了,我不想再发相同的回复了。 - Matti Virkkunen
@refp: 不,如果提问者询问的是错误的事情,首要任务是告诉他们为什么错了,然后或许向他们解释正确的方法。 - Matti Virkkunen
显示剩余2条评论

4
你不能这样做,至少不是明智的选择。虽然在jQuery ajax请求中有一个可以设置的“async”属性,但我曾经尝试过将其设置为“false”,并且遇到了严重的问题。
请重新思考你想要达到的目标:
var aft = { yourToken: '' };

aft.setToken = function (url, callback) {
    $.get(url, function (data) {
        this.yourToken = $(data).find('input[name=__RequestVerificationToken]').val();

        if (callback)
           callback.apply(this);
    }, "html");
};

然后:

aft.setToken("url.php", function() {
   alert("Token retrieved = " + this.yourToken);
});

或者,如果您的回调函数需要访问返回的数据,则可以更简单地执行以下操作:

if (callback)
    callback(data);

然后

aft.setToken("url.php", function(dataReturned) {
   alert("Ajax data retrieved = " + dataReturned);
});

到目前为止,这是最接近正确答案的,但我不明白使用对象和 apply 传递值的意义。只执行 callback($(data)...); 不就足够了吗? - Matti Virkkunen
@MattiVirkkunen - 那也可以。可能更简单。使用apply使回调函数可以访问对象的其余部分,如果回调函数关心其他内容的话。 - Adam Rackis
1
由于阻塞调用(例如同步请求)不适用于基于事件的 JavaScript 浏览器世界,因此建议不要使用这种方式进行请求。整个选项都是一个错误,希望在未来能够废弃它。 - Matti Virkkunen
@MattiVirkkunen 所以,如果一个用户在SO上询问了一件事情,我们应该尽量不要正确回答他的问题,而是引导他走另一个方向吗?(“我想传递一个变量的引用,例如var x = 1;在javascript中,这是否可能?”=>“你不能,相反转到C/C++,在那里这是最有可能的,它更好.. javascript是为失败者准备的”。我向OP提供了一个详细的答案,包括一个替代/推荐的解决方案,对我来说这已经足够被视为“正确”的答案。 - Filip Roséen - refp
1
@refp: var x = 1; 没有任何问题。然而,同步请求存在许多问题。承认失败并继续前进吧。 - Matti Virkkunen
显示剩余3条评论

0

@Adam Rackis的回调代码对我起作用。事实上,如果URL的内容是json结构,则可以直接引用字段。请注意,aft = { yourToken :'' }只是虚拟的,因为我根本没有使用字典中的值。我只想从URL获取user_id。

var aft = { yourToken: '' };
    aft.setToken = function(url, callback){
        $.get(url, function(data) {
            user_id = data[0]['user_id'];
            if (callback)
                callback(data);
        });
    };

    aft.setToken("https://XXXXXX.azurewebsites.net/.auth/me",  function(dataReturned){
        alert("You user id is " + labeler);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接