如何从异步调用返回响应?

我有一个foo发出Ajax请求的函数。我怎样才能从中回复foo

我尝试从success回调中返回值,并将响应分配给函数内部的局部变量并返回该变量,但这些方法都没有实际返回响应。

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result;}var result = foo(); // It always ends up being `undefined`.


一只萌萌小番薯
浏览 2093回答 6
6回答

凤凰求蛊

如果您没有在代码中使用jQuery,那么这个答案就适合您你的代码应该是这样的:function&nbsp;foo()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;httpRequest&nbsp;=&nbsp;new&nbsp;XMLHttpRequest(); &nbsp;&nbsp;&nbsp;&nbsp;httpRequest.open('GET',&nbsp;"/echo/json"); &nbsp;&nbsp;&nbsp;&nbsp;httpRequest.send(); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;httpRequest.responseText;}var&nbsp;result&nbsp;=&nbsp;foo();&nbsp;//&nbsp;always&nbsp;ends&nbsp;up&nbsp;being&nbsp;'undefined'Felix Kling为使用jQuery for AJAX的人写了一个很好的答案,我决定为那些没有使用jQuery的人提供替代方案。你面对的是什么这是另一个答案的“问题解释”的简短摘要,如果您在阅读本文后不确定,请阅读。AJAX中的A代表异步。这意味着发送请求(或者更确切地说是接收响应)将从正常执行流程中取出。在您的示例中,.send立即返回,并且在return result;您作为success回调传递的函数被调用之前执行下一个语句。这意味着当您返回时,您定义的侦听器尚未执行,这意味着您返回的值尚未定义。这是一个简单的比喻function&nbsp;getFive(){&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;a; &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a=5; &nbsp;&nbsp;&nbsp;&nbsp;},10); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;a;}(小提琴)a返回的值是undefined因为a=5零件尚未执行。AJAX就像这样,你在服务器有机会告诉浏览器这个值是什么之前返回值。一个可能的解决这个问题的代码重新活跃,告诉你的程序在计算完成后做什么。function&nbsp;onComplete(a){&nbsp;//&nbsp;When&nbsp;the&nbsp;code&nbsp;completes,&nbsp;do&nbsp;this &nbsp;&nbsp;&nbsp;&nbsp;alert(a);}function&nbsp;getFive(whenDone){&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;a; &nbsp;&nbsp;&nbsp;&nbsp;setTimeout(function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a=5; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;whenDone(a); &nbsp;&nbsp;&nbsp;&nbsp;},10);}这称为CPS。基本上,我们在getFive完成时传递一个动作来执行,我们告诉我们的代码在事件完成时如何反应(比如我们的AJAX调用,或者在这种情况下是超时)。用法是:getFive(onComplete);哪个应警告“5”到屏幕。(小提琴)。可能的解决方案基本上有两种解决方法:使AJAX调用同步(让我们称之为SJAX)。重构代码以使用回调正常工作。1.同步AJAX - 不要这样做!!至于同步AJAX,不要这样做!费利克斯的回答提出了一些令人信服的论据,说明为什么这是一个坏主意。总而言之,它会冻结用户的浏览器,直到服务器返回响应并创建非常糟糕的用户体验。以下是MDN对于其原因的另一个简短摘要:XMLHttpRequest支持同步和异步通信。但是,一般而言,出于性能原因,异步请求应优先于同步请求。简而言之,同步请求会阻止代码的执行......这可能会导致严重的问题......如果你必须这样做,你可以传递一个标志:这是如何:var&nbsp;request&nbsp;=&nbsp;new&nbsp;XMLHttpRequest();request.open('GET',&nbsp;'yourURL',&nbsp;false);&nbsp;&nbsp; //&nbsp;`false`&nbsp;makes&nbsp;the&nbsp;request&nbsp;synchronousrequest.send(null);if&nbsp;(request.status&nbsp;===&nbsp;200)&nbsp;{//&nbsp;That's&nbsp;HTTP&nbsp;for&nbsp;'ok' &nbsp;&nbsp;console.log(request.responseText);}2.重组代码让你的函数接受回调。在示例foo中,可以使代码接受回调。我们将告诉我们的代码在完成时如何反应foo。所以:var&nbsp;result&nbsp;=&nbsp;foo();//&nbsp;code&nbsp;that&nbsp;depends&nbsp;on&nbsp;`result`&nbsp;goes&nbsp;here变为:foo(function(result)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;code&nbsp;that&nbsp;depends&nbsp;on&nbsp;`result`});这里我们传递了一个匿名函数,但我们可以轻松地将引用传递给现有函数,使其看起来像:function&nbsp;myHandler(result)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;code&nbsp;that&nbsp;depends&nbsp;on&nbsp;`result`}foo(myHandler);有关如何完成此类回调设计的更多详细信息,请查看Felix的答案。现在,让我们定义foo自己采取相应的行动function&nbsp;foo(callback)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;httpRequest&nbsp;=&nbsp;new&nbsp;XMLHttpRequest(); &nbsp;&nbsp;&nbsp;&nbsp;httpRequest.onload&nbsp;=&nbsp;function(){&nbsp;//&nbsp;when&nbsp;the&nbsp;request&nbsp;is&nbsp;loaded &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;callback(httpRequest.responseText);//&nbsp;we're&nbsp;calling&nbsp;our&nbsp;method &nbsp;&nbsp;&nbsp;&nbsp;}; &nbsp;&nbsp;&nbsp;&nbsp;httpRequest.open('GET',&nbsp;"/echo/json"); &nbsp;&nbsp;&nbsp;&nbsp;httpRequest.send();}(小提琴)我们现在已经让我们的foo函数接受了一个在AJAX成功完成时运行的动作,我们可以通过检查响应状态是否为200并进行相应的操作来进一步扩展它(创建一个失败处理程序等)。有效解决我们的问题。如果您仍然很难理解这一点,请阅读&nbsp;MDN&nbsp;的AJAX入门指南。

慕姐4208626

XMLHttpRequest&nbsp;2(首先阅读&nbsp;Benjamin Gruenbaum和&nbsp;Felix Kling的答案)如果你不使用jQuery并想要一个很好的简短的XMLHttpRequest 2,它适用于现代浏览器,也适用于移动浏览器,我建议用这种方式:function&nbsp;ajax(a,&nbsp;b,&nbsp;c){&nbsp;//&nbsp;URL,&nbsp;callback,&nbsp;just&nbsp;a&nbsp;placeholder &nbsp;&nbsp;c&nbsp;=&nbsp;new&nbsp;XMLHttpRequest; &nbsp;&nbsp;c.open('GET',&nbsp;a); &nbsp;&nbsp;c.onload&nbsp;=&nbsp;b; &nbsp;&nbsp;c.send()}如你看到的:它比列出的所有其他功能都短。回调是直接设置的(因此没有额外的不必要的闭包)。它使用新的onload(因此您不必检查readystate && status)还有其他一些我不记得的情况会让XMLHttpRequest 1变得烦人。有两种方法可以获得此Ajax调用的响应(三种使用XMLHttpRequest var名称):最简单的:this.response或者,如果由于某种原因你bind()回调到一个类:e.target.response例:function&nbsp;callback(e){ &nbsp;&nbsp;console.log(this.response);}ajax('URL',&nbsp;callback);或者(上面的一个是更好的匿名函数总是一个问题):ajax('URL',&nbsp;function(e){console.log(this.response)});没什么比这更容易现在有些人可能会说最好使用onreadystatechange或甚至XMLHttpRequest变量名。那是错的。查看XMLHttpRequest高级功能它支持所有*现代浏览器。我可以确认,因为我使用这种方法,因为XMLHttpRequest 2存在。在我使用的所有浏览器上,我从未遇到任何类型的问题。onreadystatechange仅在您希望获取状态2的标头时才有用。使用XMLHttpRequest变量名是另一个大错误,因为你需要在onload / oreadystatechange闭包内执行回调,否则你就丢失了它。现在,如果您想使用post和FormData更复杂的东西,您可以轻松扩展此功能:function&nbsp;x(a,&nbsp;b,&nbsp;e,&nbsp;d,&nbsp;c){&nbsp;//&nbsp;URL,&nbsp;callback,&nbsp;method,&nbsp;formdata&nbsp;or&nbsp;{key:val},placeholder &nbsp;&nbsp;c&nbsp;=&nbsp;new&nbsp;XMLHttpRequest; &nbsp;&nbsp;c.open(e||'get',&nbsp;a); &nbsp;&nbsp;c.onload&nbsp;=&nbsp;b; &nbsp;&nbsp;c.send(d||null)}再一次......这是一个非常短的功能,但它确实得到和发布。用法示例:x(url,&nbsp;callback);&nbsp;//&nbsp;By&nbsp;default&nbsp;it's&nbsp;get&nbsp;so&nbsp;no&nbsp;need&nbsp;to&nbsp;setx(url,&nbsp;callback,&nbsp;'post',&nbsp;{'key':&nbsp;'val'});&nbsp;//&nbsp;No&nbsp;need&nbsp;to&nbsp;set&nbsp;post&nbsp;data或者传递一个完整的表单元素(document.getElementsByTagName('form')[0]):var&nbsp;fd&nbsp;=&nbsp;new&nbsp;FormData(form);x(url,&nbsp;callback,&nbsp;'post',&nbsp;fd);或者设置一些自定义值:var&nbsp;fd&nbsp;=&nbsp;new&nbsp;FormData();fd.append('key',&nbsp;'val')x(url,&nbsp;callback,&nbsp;'post',&nbsp;fd);如你所见,我没有实现同步...这是一件坏事。话虽如此......为什么不这么简单呢?正如评论中所提到的,使用error && synchronous确实完全打破了答案的要点。哪个是以正确方式使用Ajax的简短方法?错误处理程序function&nbsp;x(a,&nbsp;b,&nbsp;e,&nbsp;d,&nbsp;c){&nbsp;//&nbsp;URL,&nbsp;callback,&nbsp;method,&nbsp;formdata&nbsp;or&nbsp;{key:val},&nbsp;placeholder &nbsp;&nbsp;c&nbsp;=&nbsp;new&nbsp;XMLHttpRequest; &nbsp;&nbsp;c.open(e||'get',&nbsp;a); &nbsp;&nbsp;c.onload&nbsp;=&nbsp;b; &nbsp;&nbsp;c.onerror&nbsp;=&nbsp;error; &nbsp;&nbsp;c.send(d||null)}function&nbsp;error(e){ &nbsp;&nbsp;console.log('--Error--',&nbsp;this.type); &nbsp;&nbsp;console.log('this:&nbsp;',&nbsp;this); &nbsp;&nbsp;console.log('Event:&nbsp;',&nbsp;e)}function&nbsp;displayAjax(e){ &nbsp;&nbsp;console.log(e,&nbsp;this);}x('WRONGURL',&nbsp;displayAjax);在上面的脚本中,您有一个静态定义的错误处理程序,因此它不会危及该功能。错误处理程序也可用于其他功能。但要真正解决错误,唯一的方法是写一个错误的URL,在这种情况下每个浏览器都会抛出一个错误。如果您设置自定义标头,将responseType设置为blob数组缓冲区或其他任何内容,则错误处理程序可能很有用...即使你传递'POSTAPAPAP'作为方法它也不会抛出错误。即使你将'fdggdgilfdghfldj'作为formdata传递它也不会抛出错误。在第一种情况下,错误在displayAjax()under&nbsp;this.statusTextas中Method not Allowed。在第二种情况下,它只是起作用。如果您传递了正确的帖子数据,则必须在服务器端进行检查。跨域不允许自动抛出错误。在错误响应中,没有错误代码。只有this.type哪个被设置为错误。如果您完全无法控制错误,为什么要添加错误处理程序?大多数错误都在回调函数中返回displayAjax()。因此:如果您能够正确复制和粘贴URL,则无需进行错误检查。;)PS:作为我写的第一个测试x('x',displayAjax)......,它完全得到了回应...... ???&nbsp;所以我检查了HTML所在的文件夹,并且有一个名为'x.xml'的文件。因此,即使您忘记了文件的扩展名,XMLHttpRequest 2也会找到它。我好意思同步读取文件不要那样做。如果你想阻止浏览器一段时间加载一个漂亮的大.txt文件同步。function&nbsp;omg(a,&nbsp;c){&nbsp;//&nbsp;URL &nbsp;&nbsp;c&nbsp;=&nbsp;new&nbsp;XMLHttpRequest; &nbsp;&nbsp;c.open('GET',&nbsp;a,&nbsp;true); &nbsp;&nbsp;c.send(); &nbsp;&nbsp;return&nbsp;c;&nbsp;//&nbsp;Or&nbsp;c.response}现在你可以做到&nbsp;var&nbsp;res&nbsp;=&nbsp;omg('thisIsGonnaBlockThePage.txt');没有其他方法可以以非异步方式执行此操作。(是的,使用setTimeout循环......但是认真吗?)另一点是......如果你使用API或只是你自己的列表文件或者你总是为每个请求使用不同的函数...只有当你有一个页面,你总是加载相同的XML / JSON或任何你只需要一个函数。在这种情况下,修改一点Ajax函数并用您的特殊函数替换b。以上功能仅供基本使用。如果你想扩展功能......是的你可以。我使用了很多API,我在每个HTML页面中集成的第一个函数之一是这个答案中的第一个Ajax函数,只有GET ...但是你可以用XMLHttpRequest 2做很多事情:我创建了一个下载管理器(使用范围,包括简历,文件读取器,文件系统),使用画布的各种图像调整器转换器,使用base64images填充Web SQL数据库等等......但在这些情况下,您应该只创建一个函数目的...有时你需要一个blob,数组缓冲区,你可以设置标题,覆盖mimetype,还有更多......但这里的问题是如何返回Ajax响应...(我添加了一个简单的方法。)

慕运维8079593

您正在使用Ajax。我们的想法不是让它返回任何东西,而是将数据交给称为回调函数的东西,该函数处理数据。那是:function&nbsp;handleData(&nbsp;responseData&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Do&nbsp;what&nbsp;you&nbsp;want&nbsp;with&nbsp;the&nbsp;data &nbsp;&nbsp;&nbsp;&nbsp;console.log(responseData);}$.ajax({ &nbsp;&nbsp;&nbsp;&nbsp;url:&nbsp;"hi.php", &nbsp;&nbsp;&nbsp;&nbsp;... &nbsp;&nbsp;&nbsp;&nbsp;success:&nbsp;function&nbsp;(&nbsp;data,&nbsp;status,&nbsp;XHR&nbsp;)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handleData(data); &nbsp;&nbsp;&nbsp;&nbsp;}});在提交处理程序中返回任何内容都不会执行任何操作。您必须切换数据,或者直接在成功函数内执行您想要的操作。

弑天下

最简单的解决方案是创建一个JavaScript函数并调用它来进行Ajax&nbsp;success回调。function&nbsp;callServerAsync(){ &nbsp;&nbsp;&nbsp;&nbsp;$.ajax({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url:&nbsp;'...', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;success:&nbsp;function(response)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;successCallback(response); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;});}function&nbsp;successCallback(responseObj){ &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Do&nbsp;something&nbsp;like&nbsp;read&nbsp;the&nbsp;response&nbsp;and&nbsp;show&nbsp;data &nbsp;&nbsp;&nbsp;&nbsp;alert(JSON.stringify(responseObj));&nbsp;//&nbsp;Only&nbsp;applicable&nbsp;to&nbsp;JSON&nbsp;response}function&nbsp;foo(callback)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;$.ajax({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url:&nbsp;'...', &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;success:&nbsp;function(response)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;callback(null,&nbsp;response); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;});}var&nbsp;result&nbsp;=&nbsp;foo(function(err,&nbsp;result){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!err) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(result);&nbsp;&nbsp;&nbsp;&nbsp;});
打开App,查看更多内容
随时随地看视频慕课网APP