300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 如何在服务器响应后返回值 如何从异步调用返回响应?

如何在服务器响应后返回值 如何从异步调用返回响应?

时间:2023-05-19 12:24:58

相关推荐

如何在服务器响应后返回值 如何从异步调用返回响应?

问题

在一中的Ajax代表异步。这意味着发送请求(或者更确切地说是接收响应)将从正常执行流程中取出。在您的示例中,$.ajax立即返回,并且在return result;您作为success回调传递的函数被调用之前执行下一个语句。

这是一个类比,希望使同步和异步流之间的区别更加清晰:

同步

想象一下,你打电话给朋友,让他为你寻找一些东西。虽然可能需要一段时间,但是你要等电话并凝视太空,直到你的朋友给你你需要的答案。

当您进行包含“普通”代码的函数调用时,会发生同样的情况:functionfindItem(){

varitem;

while(item_not_found){

//search

}

returnitem;}varitem=findItem();//DosomethingwithitemdoSomethingElse();

尽管findItem可能需要很长时间才能执行,但之后的任何代码var item = findItem();都必须等到函数返回结果。

异步

你出于同样的原因再次打电话给你的朋友。但是这次你告诉他你很匆忙,他应该用手机给你回电话。你挂断了,离开了房子,做了你打算做的事情。一旦你的朋友给你回电话,你正在处理他给你的信息。

这正是您执行Ajax请求时发生的情况。findItem(function(item){

//Dosomethingwithitem});doSomethingElse();

而不是等待响应,执行立即继续执行Ajax调用之后的语句。为了得到响应,最终,你提供了一次收到答复要调用的函数,一个回调(注意些什么呢?叫回来?)。在调用回调之前执行该调用之后的任何语句。

解决方案(S)

拥抱JavaScript的异步特性!虽然某些异步操作提供了同步对应(“Ajax”也是如此),但通常不鼓励使用它们,尤其是在浏览器上下文中。

你问为什么这么糟糕?

JavaScript在浏览器的UI线程中运行,任何长时间运行的进程都会锁定UI,使其无响应。此外,JavaScript的执行时间有一个上限,浏览器会询问用户是否继续执行。

所有这些都是非常糟糕的用户体验。用户将无法判断一切是否正常。此外,连接速度慢的用户效果会更差。

在下文中,我们将看到三个不同的解决方案,它们都是相互叠加的:承诺async/await(ES +,如果您使用转换器或再生器,可在旧版浏览器中使用)

回调(在节点中很流行)

承诺then()(ES +,如果您使用众多承诺库中的一个,则可在旧版浏览器中使用)

这三个都在当前浏览器和节点7+中可用。

ES +:承诺与async/await

发布的ECMAScript版本引入了异步函数的语法级支持。的帮助下async和await,你可以写在“同步式”异步的。代码仍然是异步的,但它更容易阅读/理解。

async/await建立在承诺之上:async函数总是返回一个承诺。await“解包”一个承诺,或者导致承诺被解决的价值,或者如果承诺被拒绝则抛出错误。

重要提示:您只能await在async函数内部使用。目前,await尚不支持顶级,因此您可能必须创建异步IIFE(立即调用函数表达式)来启动async上下文。

你可以关于async和await的MDN。

这是一个建立在上面延迟之上的例子://Using'superagent'whichwillreturnapromise.varsuperagent=require('superagent')//Thisisisn'tdeclaredas`async`becauseit

alreadyreturnsapromisefunctiondelay(){

//`delay`returnsapromise

returnnewPromise(function(resolve,reject){

//Only`delay`isabletoresolveorrejectthepromise

setTimeout(function(){

resolve(42);//After3seconds,resolvethepromisewithvalue42

},3000);

});}asyncfunctiongetAllBooks(){

try{

//GETalistofbookIDsofthecurrentuser

varbookIDs=awaitsuperagent.get('/user/books');

//waitfor3seconds(justforthesakeofthisexample)

awaitdelay();

//GETinformationabouteachbook

returnawaitsuperagent.get('/books/ids='+JSON.stringify(bookIDs));

}catch(error){

//Ifanyoftheawaitedpromiseswasrejected,thiscatchblock

//wouldcatchtherejectionreason

returnnull;

}}//StartanIIFEtouse`await`atthetoplevel(asyncfunction(){

letbooks=awaitgetAllBooks();

console.log(books);})();

当前的浏览器和节点版本支持async/await。您还可以通过在再生器(或使用再生器的工具,如Babel)的帮助下将代码转换为ES5来支持旧环境。

让函数接受回调

回调只是传递给另一个函数的函数。其他函数可以在函数准备就绪时调用函数。在异步进程的上下文中,只要异步进程完成,就会调用回调。通常,结果将传递给回调。

在问题的示例中,您可以foo接受回调并将其用作success回调。所以这

var result = foo();

// Code that depends on 'result'

foo(function(result) {

// Code that depends on 'result'

});

这里我们定义了函数“inline”,但你可以传递任何函数引用:

function myCallback(result) {

// Code that depends on 'result'

}

foo(myCallback);

foo 本身定义如下:

function foo(callback) {

$.ajax({

// ...

success: callback

});

}

callback将foo在我们调用它时引用我们传递给它的函数,我们只是将其传递给success。即,一旦Ajax请求成功,$.ajax将调用callback并将响应传递给回调(可以参考result,因为这是我们定义回调的方式)。

您还可以在将响应传递给回调之前处理响应:

function foo(callback) {

$.ajax({

// ...

success: function(response) {

// For example, filter the response

callback(filtered_response);

}

});

}

使用回调编写代码比使用它更容易。毕竟,浏览器中的JavaScript是由事件驱动的(DOM事件)。接收Ajax响应只不过是一个事件。

当您必须使用第三方代码时可能会出现困难,但大多数问题都可以通过思考应用程序流来解决。

ES +:承诺然后()

该承诺API是ECMAScript的6(ES)的新功能,但它有很好的浏览器支持了。还有许多库实现了标准的Promises API,并提供了其他方法来简化异步函数(例如bluebird)的使用和组合。

承诺是未来价值观的容器。当promise接收到值(已解决)或取消(拒绝)时,它会通知所有想要访问此值的“侦听器”。

普通回调的优势在于它们允许您解耦代码并且更容易编写。

这是一个使用promise的简单示例:

function delay() {

// `delay` returns a promise

return new Promise(function(resolve, reject) {

// Only `delay` is able to resolve or reject the promise

setTimeout(function() {

resolve(42); // After 3 seconds, resolve the promise with value 42

}, 3000);

});

}

delay()

.then(function(v) { // `delay` returns a promise

console.log(v); // Log the value once it is resolved

})

.catch(function(v) {

// Or do something else if it is rejected

// (it would not happen in this example, since `reject` is not called).

});

应用于我们的Ajax调用,我们可以使用这样的promises:

function ajax(url) {

return new Promise(function(resolve, reject) {

var xhr = new XMLHttpRequest();

xhr.onload = function() {

resolve(this.responseText);

};

xhr.onerror = reject;

xhr.open('GET', url);

xhr.send();

});

}

ajax("/echo/json")

.then(function(result) {

// Code depending on result

})

.catch(function() {

// An error occurred

});

描述承诺提供的所有优点超出了本答案的范围,但如果您编写新代码,则应认真考虑它们。它们提供了很好的抽象和代码分离。

旁注:jQuery的延迟对象

延迟对象是jQuery的promises自定义实现(在Promise API标准化之前)。它们的行为几乎与承诺相似,但暴露出略微不同的API。

jQuery的每个Ajax方法都已经返回一个“延迟对象”(实际上是一个延迟对象的承诺),你可以从你的函数返回:

function ajax() {

return $.ajax(...);

}

ajax().done(function(result) {

// Code depending on result

}).fail(function() {

// An error occurred

});

旁注:承诺陷阱

请记住,promises和deferred对象只是未来值的容器,它们本身并不是值。例如,假设您有以下内容:

function checkPassword() {

return $.ajax({

url: '/password',

data: {

username: $('#username').val(),

password: $('#password').val()

},

type: 'POST',

dataType: 'json'

});

}

if (checkPassword()) {

// Tell the user they're logged in

}

此代码误解了上述异步问题。具体来说,$.ajax()在检查服务器上的“/ password”页面时不会冻结代码 - 它会向服务器发送请求,并在等待时立即返回jQuery Ajax Deferred对象,而不是服务器的响应。这意味着该if语句将始终获取此Deferred对象,将其视为true,并继续进行,就像用户已登录一样。不好。

但修复很简单:

checkPassword()

.done(function(r) {

if (r) {

// Tell the user they're logged in

} else {

// Tell the user their password was bad

}

})

.fail(function(x) {

// Tell the user something bad happened

});

不推荐:同步“Ajax”调用

正如我所提到的,一些(!)异步操作具有同步对应物。我不提倡使用它们,但为了完整起见,以下是执行同步调用的方法:

没有jQuery

如果直接使用XMLHTTPRequest对象,则将false第三个参数传递给.open。

jQuery的

如果使用jQuery,则可以将async选项设置为false。请注意,自jQuery 1.8以来不推荐使用此选项。然后,您可以仍然使用success回调或访问jqXHR对象的responseText属性:functionfoo(){

varjqXHR=$.ajax({

//...

async:false

});

returnjqXHR.responseText;}

如果使用任何其他的jQuery的Ajax的方法,例如$.get,$.getJSON等等,必须将其改为$.ajax(因为你只能传递配置参数$.ajax)。

当心!无法生成同步JSONP请求。JSONP本质上总是异步的(甚至不考虑这个选项的另一个原因)。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。