jQuery:在ajax调用成功后返回数据

538

我有类似这样的东西,它是对一个脚本的简单调用,返回一个字符串值。

function testAjax() {
    $.ajax({
      url: "getvalue.php",  
      success: function(data) {
         return data; 
      }
   });
}

但是如果我像这样调用某个东西

var output = testAjax(svar);  // output will be undefined...

那我怎么返回这个值呢? 下面的代码似乎也不起作用...

function testAjax() {
    $.ajax({
      url: "getvalue.php",  
      success: function(data) {

      }
   });
   return data; 
}

1
这可能会对你有所帮助。http://codingbin.com/get-return-data-ajax-call/ - Manoj Dhiman
5个回答

450

注意:此答案是在2010年2月编写的。
请参见底部2015、2016和2017年的更新。

您无法从异步函数中返回任何内容。您可以返回一个promise。我在回答以下问题时解释了jQuery中的promises工作原理:

如果您能解释为什么您想要返回数据以及稍后想要使用它做什么,那么我可能能够给您提供更具体的答案。

通常情况下,不是:

function testAjax() {
  $.ajax({
    url: "getvalue.php",  
    success: function(data) {
      return data; 
    }
  });
}

你可以像这样编写你的testAjax函数:
function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

然后你可以像这样获取你的 Promise:
var promise = testAjax();

你可以存储你的承诺,你可以传递它,你可以在函数调用中使用它作为参数,并且你可以从函数中返回它,但是当你最终想要使用由AJAX调用返回的数据时,你必须这样做:

promise.success(function (data) {
  alert(data);
});

如果您的数据此时可用,那么该函数将立即被调用。如果不可用,则会在数据可用时立即调用。
所有这样做的重点是因为您在调用$.ajax后数据不会立即可用,因为它是异步的。Promises是一个很好的抽象函数,可以说:我不能返回你数据,因为我还没有它,而且我不想阻塞并让你等待,所以这里有一个承诺,稍后你就能使用它,或者只是把它给别人并完成它。
请参见此DEMO
更新(2015)
目前(截至2015年3月),jQuery Promises与Promises/A+规范不兼容,这意味着它们可能与其他Promises/A+符合实现不太协作。
但是,即将推出的版本3.x中的jQuery Promises将与Promises/A+规范兼容(感谢Benjamin Gruenbaum指出)。当前(截至2015年5月),jQuery的稳定版本为1.x和2.x。
我在2011年3月所解释的是一种使用jQuery Deferred Objects以异步方式执行某些操作的方法,而在同步代码中则通过返回值来实现。
但同步函数调用可以做两件事情——如果可能的话,它可以返回一个值;如果不能返回值,则会抛出异常。Promises/A+以一种几乎和同步代码中的异常处理一样强大的方式解决了这两种用例。jQuery版本可以很好地处理相当于返回值的内容,但相当于复杂异常处理的内容有些棘手。
特别是,在同步代码中异常处理的整个重点不仅在于放弃并显示友好的消息,而在于尝试修复问题并继续执行,或者可能为程序的其他部分重新抛出相同或不同的异常以进行处理。在同步代码中,您拥有一个调用堆栈。在异步调用中,您没有调用堆栈,因此根据Promises/A+规范所需的高级异常处理确实可以帮助您编写能够处理错误和异常的代码,即使是对于复杂的用例。
关于jQuery和其他实现之间的差异以及如何将jQuery promises转换为符合Promises/A+标准的内容,请参见Kris Kowal等人在Q库维基上发布的Coming from jQuery,以及Jake Archibald在HTML5 Rocks上发布的Promises arrive in JavaScript
如何返回一个真正的promise?

我上面的示例中的函数:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

返回一个jqXHR对象,它是一个jQuery Deferred Object

要使其返回一个真正的promise,您可以将其更改为 - 使用Q Wiki中的方法

function testAjax() {
  return Q($.ajax({
      url: "getvalue.php"
  }));
}

或者,使用HTML5 Rocks文章中的方法

function testAjax() {
  return Promise.resolve($.ajax({
      url: "getvalue.php"
  }));
}

这个 Promise.resolve($.ajax(...)) 也是在 promise模块文档中解释 的,它应该可以与ES6的 Promise.resolve()一起使用。
要在今天使用ES6 Promises,您可以使用Jake Archibald的es6-promise模块的polyfill()
要查看在没有polyfill的情况下可以使用ES6 Promises的地方,请参见:Can I use: Promises
有关更多信息,请参见:

jQuery的未来

从3.x版本开始(截至2015年5月,当前稳定版本为1.x和2.x),jQuery的未来版本将与Promises/A+规范兼容(感谢Benjamin Gruenbaum在评论中指出)。“我们已经决定了两个变化,即Deferred实现的Promise/A+兼容性[...]”jQuery 3.0和Web开发的未来)。更多信息请参见:Dave Methvin的jQuery 3.0:下一代和Paul Krill的jQuery 3.0:更多互操作性,更少的Internet Explorer

有趣的讲话

更新(2016)

ECMA-262,第6版,第14.2节中有一种新的语法叫做箭头函数,可以用来进一步简化上面的示例。

使用jQuery API,而不是:

promise.success(function (data) {
  alert(data);
});

你可以编写:

promise.success(data => alert(data));

或使用 Promises/A+ API:

promise.then(data => alert(data));

记得始终使用拒绝处理程序,无论是与以下哪种情况一起使用:

promise.then(data => alert(data), error => alert(error));

或者使用:
promise.then(data => alert(data)).catch(error => alert(error));

查看这个答案,了解为什么您应该始终使用带有 Promise 的 rejection handlers:

当然,在此示例中,您可以仅使用 promise.then(alert),因为您只是使用与回调相同的参数调用 alert,但箭头语法更通用,让您编写类似以下内容的内容:

promise.then(data => alert("x is " + data.x));

并非每个浏览器都支持此语法,但在某些情况下,您可以确定代码将在哪个浏览器上运行 - 例如编写Chrome扩展程序Firefox插件或使用Electron、NW.js或AppJS的桌面应用程序(有关详细信息,请参见此答案)。

有关箭头函数的支持,请参见:

更新(2017年)

现在有一种全新的语法叫做异步函数,使用一个新的await关键字,代替以下代码:

functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

让您编写:

try {
    let data = await functionReturningPromise();
    console.log('Data:', data);
} catch (error) {
    console.log('Error:', error);
}

您只能在使用 async 关键字创建的函数内部使用它。有关更多信息,请参见:

有关浏览器支持,请参见:

有关Node的支持,请参见:

在不支持 asyncawait 的地方,您可以使用 Babel:

或者使用稍微不同的语法,像在co或Bluebird协程中基于生成器的方法:

更多信息

关于 Promise 的其他问题,请参阅以下详细信息:


6
完美的回答!只是需要为用户添加一个附注,这在jQuery 1.4版本中不起作用。 - Trevor
9
非常有帮助。我只是跳过了步骤var promise = testAjax(),并改为使用下面的代码:testAjax().success(function (data) { alert(data); }); - isurfbecause
@rsp 确实是个好答案!但我跟着你的演示代码走,似乎调用了两次ajax(有其他人也注意到了吗?)。 - thicolares
值得一提的是,Promises/A+承诺在jQuery 3.0分支中确实存在。 - Benjamin Gruenbaum
1
@AlexG 在我的例子中,你可以使用 promise.success(function (data) { alert(data.users[0].id); alert(data.prices[x]); }); 或类似的方式来代替 promise.success(function (data) { alert(data); });。如果你在 success 回调函数中(或者如果你正在使用 Promises/A+ API 的话,在 then 回调函数中)获取数据,则可以获得带有所有属性的数据。 - rsp
显示剩余4条评论

427

如果使用同步调用而非异步调用,唯一返回函数数据的方法将冻结浏览器以等待响应。

可以传入一个处理结果的回调函数:

function testAjax(handleData) {
  $.ajax({
    url:"getvalue.php",  
    success:function(data) {
      handleData(data); 
    }
  });
}

按照以下方式调用:

testAjax(function(output){
  // here you use the output
});
// Note: the call won't wait for the result,
// so it will continue with the code here while waiting.

1
@iamsirjayesh 我可以为您做数学,只需要5.5年!...不过这个答案可能会有所帮助。 - Cirelli94
@Cirelli94:我数学太差了 :p - Hunterr
12
successе’ҢerrorеңЁjQuery 1.8дёӯе·Із»Ҹиў«ејғз”ЁгҖӮдҪ еә”иҜҘејҖе§ӢдҪҝз”Ё.done()е’Ң.fail()гҖӮиҜ·еҸӮйҳ…ж–ҮжЎЈгҖӮ - FibreChips
4
被弃用的是回调操作函数(例如.error、.success),而不是ajax方法的参数。请参见此线程中的评论。https://dev59.com/emgu5IYBdhLWcg3w_L7J#10931891 - EGS
1
@Mike:问题在于,除非你有一个TARDIS,否则你无法从调用中获取结果。由于调用是异步的,结果将在调用返回后到达。您可以查看其他答案中提供的承诺,这将使您能够从调用中返回某些内容,即使结果尚未到达。无论如何,您都必须等待结果,承诺只是让您在代码的不同部分执行此操作。 - Guffa
显示剩余4条评论

224

你可以将async选项设置为false 并且在ajax调用之外返回。

function testAjax() {
    var result="";
    $.ajax({
      url:"getvalue.php",
      async: false,  
      success:function(data) {
         result = data; 
      }
   });
   return result;
}

17
你的解决方案是完全有效的。我只想强调不要立即在成功回调函数内返回值,而是在 .ajax 函数调用的外部返回值。否则,你会得到 undefined。 - anar khalilov
2
有没有办法在 async:true 的情况下使用这个函数? - vivex
17
大多数情况下,async: falsewhatwg规范中已被弃用。当使用async: false进行调用时,Google Chrome会在控制台中发出警告。目前看来w3c规范尚未弃用它。注意:此处仅为翻译,不包含解释或其他内容。 - Frédéric
这对我没用...我的返回语句中结果为未定义! - Avdhut Vaidya
1
使用 async: false 可以让我的代码工作,但获取数据需要一些时间。也许这就是为什么它即将被省略的原因。有没有解决方案?现在应该采用什么正确的方法? - kapitan
显示剩余5条评论

0

不知道你们是否已经解决了,但我建议另一种方法来解决它,而且它有效 :)

    ServiceUtil = ig.Class.extend({
        base_url : 'someurl',

        sendRequest: function(request)
        {
            var url = this.base_url + request;
            var requestVar = new XMLHttpRequest();
            dataGet = false;

            $.ajax({
                url: url,
                async: false,
                type: "get",
                success: function(data){
                    ServiceUtil.objDataReturned = data;
                }
            });
            return ServiceUtil.objDataReturned;                
        }
    })

所以这里的主要思想是,通过添加async: false,你可以让所有东西等待数据被检索。然后将其分配给类的静态变量,一切都神奇地运作 :)


8
这个想法已经在这个答案中提出了 (https://dev59.com/FG435IYBdhLWcg3wmxbz#7891780)。总的来说,进行同步的Ajax请求并不是一个好主意。 - Felix Kling

-14

参考jQuery文档示例: http://api.jquery.com/jQuery.ajax/ (大约在页面的2/3位置)

您可能正在寻找以下代码:

    $.ajax({
     url: 'ajax/test.html',
     success: function(data) {
     $('.result').html(data);
     alert('Load was performed.');
   }
});

同一页...往下滑。


1
如果需要在另一个函数内进行进一步处理,你会如何将其传递到那里? - Eyad Mohammed Osama

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