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

Fra*_*sco 447 javascript ajax jquery

我有这样的东西,它是一个简单的调用脚本,给我一个值,一个字符串..

function testAjax() {
    $.ajax({
      url: "getvalue.php",  
      success: function(data) {
         return data; 
      }
   });
}
Run Code Online (Sandbox Code Playgroud)

但如果我打电话给这样的话

var output = testAjax(svar);  // output will be undefined...
Run Code Online (Sandbox Code Playgroud)

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

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

      }
   });
   return data; 
}
Run Code Online (Sandbox Code Playgroud)

rsp*_*rsp 396

注意:此答案于2010年2月撰写.
请参阅底部2015年,2016年和2017年的更新.

您不能从异步函数返回任何内容.你能回报的是一个承诺.我在回答这些问题时解释了jQuery中的promises是如何工作的:

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

通常,而不是:

function testAjax() {
  $.ajax({
    url: "getvalue.php",  
    success: function(data) {
      return data; 
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样编写testAjax函数:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}
Run Code Online (Sandbox Code Playgroud)

然后你就可以得到这样的承诺:

var promise = testAjax();
Run Code Online (Sandbox Code Playgroud)

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

promise.success(function (data) {
  alert(data);
});
Run Code Online (Sandbox Code Playgroud)

(有关简化语法,请参阅下面的更新.)

如果此时您的数据可用,则将立即调用此函数.如果不是,那么只要数据可用就会调用它.

完成所有这一切的重点是,在调用$ .ajax之后,您的数据不可用,因为它是异步的.Promises是一个很好的抽象函数来说:我不能把数据归还给你,因为我还没有它,而且我不想阻止你让你等待所以这里是一个承诺,你将能够以后使用它,或者只是把它交给别人并完成它.

看这个DEMO.

更新(2015年)

目前(截至2015年3月)jQuery Promises与Promises/A +规范不兼容,这意味着它们可能与其他Promises/A +一致的实现不能很好地协作.

然而,即将推出的版本3.x中的jQuery Promise 与Promises/A +规范兼容(感谢Benjamin Gruenbaum指出它).目前(截至2015年5月)jQuery的稳定版本是1.x和2.x.

我上面解释的(2011年3月)是一种使用jQuery Deferred Objects异步执行某些操作的方法,通过返回值可以实现同步代码.

但是同步函数调用可以做两件事 - 它可以返回一个值(如果可以)或抛出一个异常(如果它不能返回一个值).Promises/A +以与同步代码中的异常处理一样强大的方式处理这两个用例.jQuery版本处理相当于返回一个很好的值,但相当于复杂的异常处理有点问题.

特别是,同步代码中异常处理的重点不仅仅是放弃一个好消息,而是试图修复问题并继续执行,或者可能为程序的其他部分重新抛出相同或不同的异常.处理.在同步代码中,您有一个调用堆栈.在异步调用中,您不需要Promises/A +规范所要求的Promise内部的高级异常处理可以真正帮助您编写代码,即使对于复杂的用例,也能以有意义的方式处理错误和异常.

对于jQuery和其他实现之间的差异,以及如何将jQuery promises转换为Promises/A +兼容,请参阅Kris Kowal等人的jQuery来自.关于Q库维基和Promises由Jake Archibald在HTML5 Rocks上使用JavaScript.

如何回报真正的承诺

上面例子中的函数:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}
Run Code Online (Sandbox Code Playgroud)

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

为了让它返回真正的承诺,您可以使用Q维基中的方法将其更改为:

function testAjax() {
  return Q($.ajax({
      url: "getvalue.php"
  }));
}
Run Code Online (Sandbox Code Playgroud)

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

function testAjax() {
  return Promise.resolve($.ajax({
      url: "getvalue.php"
  }));
}
Run Code Online (Sandbox Code Playgroud)

Promise.resolve($.ajax(...))也是模块文档中解释的promise内容,它应该适用于ES6Promise.resolve().

要使用ES6 Promises,您可以使用Jake Archibald的es6-promise模块polyfill().

要查看在没有polyfill的情况下可以使用ES6 Promises的位置,请参阅:我可以使用:Promises.

有关详情,请参阅:

jQuery的未来

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

有趣的谈话

更新(2016年)

ECMA-262,第6版,第14.2节中有一种称为箭头函数的新语法,可用于进一步简化上述示例.

使用jQuery API,而不是:

promise.success(function (data) {
  alert(data);
});
Run Code Online (Sandbox Code Playgroud)

你可以写:

promise.success(data => alert(data));
Run Code Online (Sandbox Code Playgroud)

或使用Promises/A + API:

promise.then(data => alert(data));
Run Code Online (Sandbox Code Playgroud)

请记住始终使用拒绝处理程序:

promise.then(data => alert(data), error => alert(error));
Run Code Online (Sandbox Code Playgroud)

或者:

promise.then(data => alert(data)).catch(error => alert(error));
Run Code Online (Sandbox Code Playgroud)

请参阅此答案,了解为什么您应该始终使用具有承诺的拒绝处理程序:

当然在这个例子中你可以使用,promise.then(alert)因为你只是alert使用与回调相同的参数调用,但是箭头语法更通用,并允许你编写如下内容:

promise.then(data => alert("x is " + data.x));
Run Code Online (Sandbox Code Playgroud)

并非所有浏览器都支持此语法,但在某些情况下,您确定代码将运行在哪个浏览器上 - 例如,使用Electron,NW.js或编写Chrome扩展程序,Firefox附加组件或桌面应用程序时AppJS(详见答案).

有关箭头功能的支持,请参阅:

更新(2017年)

现在还有一种更新的语法称为异步函数,其中包含一个新的await关键字而不是此代码:

functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));
Run Code Online (Sandbox Code Playgroud)

让你写:

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

您只能在使用async关键字创建的函数内部使用它.有关详细信息,请参阅:

有关浏览器的支持,请参阅:

有关Node的支持,请参阅:

在您没有本机支持的地方async,await您可以使用Babel:

或者使用略有不同的语法,基于生成器的方法,如co或者Bluebird协同程序:

更多信息

关于更多细节的承诺的其他一些问题:

  • 这有很大帮助.我刚跳过`var promise = testAjax()`并执行了`testAjax().success(function(data){alert(data);});` (9认同)
  • 完美的答案!只是为用户添加旁注,这不适用于jQuery ver 1.4. (6认同)
  • 当做某事的方式每年都在变化时,真是太好了。 (3认同)

Guf*_*ffa 373

从函数返回数据的唯一方法是进行同步调用而不是异步调用,但这会在等待响应时冻结浏览器.

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

function testAjax(handleData) {
  $.ajax({
    url:"getvalue.php",  
    success:function(data) {
      handleData(data); 
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

像这样称呼它:

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.
Run Code Online (Sandbox Code Playgroud)

  • 在jQuery 1.8中不推荐使用`success`和`error`.你应该开始使用`.done()`和`.fail()`.请参阅[文档](http://api.jquery.com/jquery.ajax/). (10认同)
  • 不推荐使用的是回调操作函数(例如.error,.success),而不是ajax方法的参数.请参阅此主题中的注释./sf/answers/765232401/ (2认同)

小智 181

您可以将async选项添加到false 返回到ajax调用之外.

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

  • 对于大多数用例,`async:false`现在已在[whatwg规范](https://xhr.spec.whatwg.org/#the-open%28%29-method)中弃用.当使用`async:false`进行调用时,Google Chrome已在其控制台中对此进行了警告.[w3c规范](http://www.w3.org/TR/XMLHttpRequest/#the-open%28%29-method)似乎还没有弃用它. (15认同)
  • 您的解决方案完全有效.我只想强调不在成功回调中立即返回值的重要性,而是在.ajax函数调用之外.否则你将得到未定义. (13认同)
  • 有没有办法将这个函数与 async:true 一起使用? (2认同)

归档时间:

查看次数:

987080 次

最近记录:

9 年,1 月 前