如何从异步电话中返回响应?
如何从函数 foo
中返回响应/结果,该是异步请求的?
我正在尝试从回调中返回值,并将结果分配给功能内部的局部变量并返回该值,但是这些方法实际上都没有返回响应 - 它们都返回
undefined
>或变量结果的初始值
是。
接受回调的异步函数的示例(使用jQuery的 ajax
函数):
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result; // It always returns `undefined`
}
使用node.js:
function foo() {
var result;
fs.readFile("path/to/file", function(err, data) {
result = data;
// return data; // <- I tried that one as well
});
return result; // It always returns `undefined`
}
使用<<代码>然后承诺的块:
function foo() {
var result;
fetch(url).then(function(response) {
result = response;
// return response; // <- I tried that one as well
});
return result; // It always returns `undefined`
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
以下是一些处理异步请求的方法:
示例:jQuery延期递延实现以与多个请求一起使用
Here are some approaches to work with asynchronous requests:
Example: jQuery deferred implementation to work with multiple requests
简短答案:您的
foo()
方法立即返回,而$ ajax()
呼叫在函数返回后执行异步 em>。问题是,一旦返回,就如何或何处存储了通过异步调用检索的结果。该线程中已经提供了几种解决方案。也许最简单的方法是将对象传递到
foo()
方法,并在异步调用完成后将结果存储在该对象的成员中。请注意,调用
foo()
仍然将返回无用。但是,异步调用的结果现在将存储在result.Response
中。Short answer: Your
foo()
method returns immediately, while the$ajax()
call executes asynchronously after the function returns. The problem is then how or where to store the results retrieved by the async call once it returns.Several solutions have been given in this thread. Perhaps the easiest way is to pass an object to the
foo()
method, and to store the results in a member of that object after the async call completes.Note that the call to
foo()
will still return nothing useful. However, the result of the async call will now be stored inresult.response
.在
foo()
成功中使用callback()
函数。以这种方式尝试。这很容易理解。
Use a
callback()
function inside thefoo()
success.Try it in this way. It is simple and easy to understand.
使用承诺
对此问题的最完美答案是使用
Promise
。用法
,但等等...!
使用承诺有问题!
我们为什么要使用自己的自定义承诺?
我已经使用了一段时间,直到我发现旧浏览器存在错误:
因此我决定将自己的诺言类实施 es3的承诺类,如果未定义,请 javascript编译器。只需在主代码之前添加此代码,然后安全地使用Promise!
Using Promise
The most perfect answer to this question is using
Promise
.Usage
But wait...!
There is a problem with using promises!
Why should we use our own custom Promise?
I was using this solution for a while until I figured out there is an error in old browsers:
So I decided to implement my own Promise class for ES3 to below JavaScript compilers if it's not defined. Just add this code before your main code and then safely use Promise!
使用ES2017,您应该将其作为函数声明。
并这样执行。
或承诺语法。
演示上述代码的堆栈片段。
Using ES2017 you should have this as the function declaration.
And executing it like this.
Or the Promise syntax.
Stack Snippet that demonstrates the code above.
当然,有许多方法,例如同步请求,保证,但是根据我的经验,我认为您应该使用回调方法。 JavaScript的异步行为很自然。
因此,您的代码片段可以重写有些不同:
Of course there are many approaches like synchronous request, promise, but from my experience I think you should use the callback approach. It's natural to asynchronous behavior of JavaScript.
So, your code snippet can be rewritten to be a little different:
问题是:
哪个可以解释为:
解决方案将是避免回调,并结合 Promises 和 async/等待。
我想为Ajax请求举一个示例。
(尽管可以用JavaScript编写,但我更喜欢用python编写它,然后使用 transcrypt
a >
s
:定义一个返回a Promise 的函数,在这种情况下,AJAX调用:
使用 asynchronous 代码,就好像它是同步:
The question was:
which can be interpreted as:
The solution will be to avoid callbacks, and use a combination of Promises and async/await.
I would like to give an example for an Ajax request.
(Although it can be written in JavaScript, I prefer to write it in Python, and compile it to JavaScript using Transcrypt. It will be clear enough.)
Let’s first enable jQuery usage, to have
$
available asS
:Define a function which returns a Promise, in this case an Ajax call:
Use the asynchronous code as if it were synchronous:
a in
这是一个类比,希望能使同步和异步流更清晰地之间有所不同:
同步
想象您打电话给朋友,并要求他为您寻找东西。尽管可能需要一段时间,但您在电话上等待太空,直到您的朋友给您所需的答案。
当您进行包含“正常”代码的函数调用时,也会发生同样的情况:
即使
FindItem
可能需要很长时间才能执行,var item = var item = findItem(); 必须等待,直到函数返回结果。
异步
出于同样的原因, 您再次致电您的朋友。但是这次您告诉他您很着急,他应该在手机上给您回电。您挂断电话,离开房子,做您计划做的任何事情。一旦您的朋友给您回电,您就会处理他给您的信息。
这就是您执行AJAX请求时发生的事情。
执行并没有等待响应,而是立即继续执行,并且执行AJAX调用后的语句。为了最终获得响应,您提供了一个函数,一旦收到响应,a challback (请注意某件事?回电?)。在调用回调之前执行该呼叫后的任何语句。
解决方案
包含JavaScript!的异步性质,而某些异步操作提供同步的对应物(“ Ajax”也是如此),通常不愿意使用它们,尤其是在浏览器上下文中。
你为什么问不好?
JavaScript在浏览器的UI线程中运行,任何长期运行的过程都会锁定UI,从而使其无反应。此外,JavaScript的执行时间有一个上限,浏览器将询问用户是否继续执行。
所有这些都导致了非常糟糕的用户体验。用户将无法分辨出一切工作正常。此外,对于连接缓慢的用户而言,效果会更糟。
在以下内容中,我们将查看三种彼此之间建立的不同解决方案:
ynnc/等待
(ES2017++,如果您使用的话,可在较旧的浏览器中使用transpiler或recenener)then()
(ES2015+)承诺(ES2015+)浏览器如果使用众多承诺库之一)所有三个都在当前浏览器中可用,节点7+。
es2017+:promise
async/等待
2017年在2017年发布的ecmascript版本引入了 andtax-level support syynChronionus函数。借助
async
和等待
,您可以以“同步样式”编写异步。该代码仍然具有异步,但是阅读/理解更容易。异步/等待
在承诺之上构建:async
函数始终返回承诺。等待
“取消包裹”的承诺,并且如果拒绝承诺,则可以解决承诺的价值或丢弃错误。重要:您只能在
async
函数或 en-us/doc/web/javaScript/guide/模块“ rel =“ noreferrer”> javascript模块。顶级等待
在模块之外不支持,因此您可能必须制作一个异步(立即调用函数表达式)启动async
上下文如果不使用模块。您可以阅读有关 noreferrer“>
async
和等待MDN上。
这是详细列出 delay 函数
finditem()
上面的示例:当前浏览器和 node 版本支持
async/aync/negait
。您还可以在 recenererator 的帮助下,通过将代码转换为ES5来支持旧环境。 ,例如 babel )。让函数接受回调
一个回调是当函数1传递给函数2时。函数2可以在准备就绪时调用函数1。在异步过程的上下文中,每当完成异步过程时,都会调用回调。通常,结果将传递给回调。
在问题的示例中,您可以进行
foo
接受回调,并将其用作Success
回调。因此,这将成为
这里定义“内联”函数,但是您可以传递任何函数参考:
foo
本身定义如下:callback
将参考我们传递给<<<的函数。代码> foo 我们调用它,然后将其传递给Success
。即,一旦AJAX请求成功,$。ajax
将调用回调
,然后将响应传递给回调(可以使用result> Result
来参考。 ,因为这就是我们定义回调的方式)。您还可以在将响应传递给回调之前处理:
使用回调编写代码比看起来更容易。毕竟,浏览器中的JavaScript是事件驱动的(DOM事件)。接收Ajax响应只是事件。
当您必须使用第三方代码时,可能会出现困难,但是只要考虑应用程序流程,就可以解决大多数问题。
ES2015+: the
一个href =“ https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_object/global_objects/promise” rel =“ noreferrer”> Promise api ),但是它有很好的浏览器支持。也有许多库可以实现标准承诺API并提供其他方法来减轻异步功能的使用和组成(例如,)。
承诺是未来值的容器。当承诺收到值(已解决的)或取消(拒绝)时,它会通知所有想访问此值的“听众”。
比普通回调的优势在于,它们允许您将代码解除,并且更容易撰写。
这是使用承诺的示例:
应用于我们的Ajax电话,我们可以使用这样的承诺:
描述承诺提供的所有优势超出了此答案的范围,但是如果您编写新代码,则应认真考虑它们。它们提供了很好的抽象和您的代码分离。
有关承诺的更多信息: html5 rocks -javascript Promises promises 。
旁注:jQuery的延期对象
延迟对象标准化)。他们的行为几乎像承诺,但暴露了略有不同的API。
jQuery的每种AJAX方法已经返回一个“递延对象”(实际上是递延对象的承诺),您可以从函数中返回:
侧面注意:promise gotchas new Chep
牢记承诺和递延对象只是容器 /em>对于未来的价值,它们不是价值本身。例如,假设您有以下内容:
此代码误解了上述异步问题。具体来说,
$。ajax()
在检查服务器上的“/密码”页面时不会冻结代码 - 它将请求发送到服务器,并且在等待时,它立即返回jQuery AJAX递延对象,而不是服务器的响应。这意味着如果
语句将始终获取此延期对象,请将其视为true
,然后继续以用户登录。不好。但是修复程序很容易:
不推荐:我提到的同步“ ajax”调用
,一些(!)异步操作具有同步的对应物。我不主张他们的使用,但为了完整的缘故,这是您执行同步呼叫的方式:
如果
直接使用
xmlhttprequest
对象,将false
作为第三个参数作为.open
。jQuery
如果您使用 jquery ,您可以设置
async
选项false
。请注意,由于jQuery 1.8,此选项是弃用。然后,您可以仍然使用
成功
回调,或访问ResponseText
jqxhr对象:如果您使用任何其他jquery ajax方法,例如
$。get
,$。getjson
等。 。抬头!无法同步 jsonp 请求。 JSONP本质上总是异步的(甚至不考虑此选项的另一个原因)。
The problem
The A in Ajax stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example,
$.ajax
returns immediately and the next statement,return result;
, is executed before the function you passed assuccess
callback was even called.Here is an analogy which hopefully makes the difference between synchronous and asynchronous flow clearer:
Synchronous
Imagine you make a phone call to a friend and ask him to look something up for you. Although it might take a while, you wait on the phone and stare into space, until your friend gives you the answer that you needed.
The same is happening when you make a function call containing "normal" code:
Even though
findItem
might take a long time to execute, any code coming aftervar item = findItem();
has to wait until the function returns the result.Asynchronous
You call your friend again for the same reason. But this time you tell him that you are in a hurry and he should call you back on your mobile phone. You hang up, leave the house, and do whatever you planned to do. Once your friend calls you back, you are dealing with the information he gave to you.
That's exactly what's happening when you do an Ajax request.
Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. To get the response eventually, you provide a function to be called once the response was received, a callback (notice something? call back ?). Any statement coming after that call is executed before the callback is called.
Solution(s)
Embrace the asynchronous nature of JavaScript! While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context.
Why is it bad do you ask?
JavaScript runs in the UI thread of the browser and any long-running process will lock the UI, making it unresponsive. Additionally, there is an upper limit on the execution time for JavaScript and the browser will ask the user whether to continue the execution or not.
All of this results in a really bad user experience. The user won't be able to tell whether everything is working fine or not. Furthermore, the effect will be worse for users with a slow connection.
In the following we will look at three different solutions that are all building on top of each other:
async/await
(ES2017+, available in older browsers if you use a transpiler or regenerator)then()
(ES2015+, available in older browsers if you use one of the many promise libraries)All three are available in current browsers, and node 7+.
ES2017+: Promises with
async/await
The ECMAScript version released in 2017 introduced syntax-level support for asynchronous functions. With the help of
async
andawait
, you can write asynchronous in a "synchronous style". The code is still asynchronous, but it's easier to read/understand.async/await
builds on top of promises: anasync
function always returns a promise.await
"unwraps" a promise and either result in the value the promise was resolved with or throws an error if the promise was rejected.Important: You can only use
await
inside anasync
function or in a JavaScript module. Top-levelawait
is not supported outside of modules, so you might have to make an async IIFE (Immediately Invoked Function Expression) to start anasync
context if not using a module.You can read more about
async
andawait
on MDN.Here is an example that elaborates the delay function
findItem()
above:Current browser and node versions support
async/await
. You can also support older environments by transforming your code to ES5 with the help of regenerator (or tools that use regenerator, such as Babel).Let functions accept callbacks
A callback is when function 1 is passed to function 2. Function 2 can call function 1 whenever it is ready. In the context of an asynchronous process, the callback will be called whenever the asynchronous process is done. Usually, the result is passed to the callback.
In the example of the question, you can make
foo
accept a callback and use it assuccess
callback. So thisbecomes
Here we defined the function "inline" but you can pass any function reference:
foo
itself is defined as follows:callback
will refer to the function we pass tofoo
when we call it and we pass it on tosuccess
. I.e. once the Ajax request is successful,$.ajax
will callcallback
and pass the response to the callback (which can be referred to withresult
, since this is how we defined the callback).You can also process the response before passing it to the callback:
It's easier to write code using callbacks than it may seem. After all, JavaScript in the browser is heavily event-driven (DOM events). Receiving the Ajax response is nothing else but an event.
Difficulties could arise when you have to work with third-party code, but most problems can be solved by just thinking through the application flow.
ES2015+: Promises with then()
The Promise API is a new feature of ECMAScript 6 (ES2015), but it has good browser support already. There are also many libraries which implement the standard Promises API and provide additional methods to ease the use and composition of asynchronous functions (e.g., bluebird).
Promises are containers for future values. When the promise receives the value (it is resolved) or when it is canceled (rejected), it notifies all of its "listeners" who want to access this value.
The advantage over plain callbacks is that they allow you to decouple your code and they are easier to compose.
Here is an example of using a promise:
Applied to our Ajax call we could use promises like this:
Describing all the advantages that promise offer is beyond the scope of this answer, but if you write new code, you should seriously consider them. They provide a great abstraction and separation of your code.
More information about promises: HTML5 rocks - JavaScript Promises.
Side note: jQuery's deferred objects
Deferred objects are jQuery's custom implementation of promises (before the Promise API was standardized). They behave almost like promises but expose a slightly different API.
Every Ajax method of jQuery already returns a "deferred object" (actually a promise of a deferred object) which you can just return from your function:
Side note: Promise gotchas
Keep in mind that promises and deferred objects are just containers for a future value, they are not the value itself. For example, suppose you had the following:
This code misunderstands the above asynchronous issues. Specifically,
$.ajax()
doesn't freeze the code while it checks the '/password' page on your server - it sends a request to the server and while it waits, it immediately returns a jQuery Ajax Deferred object, not the response from the server. That means theif
statement is going to always get this Deferred object, treat it astrue
, and proceed as though the user is logged in. Not good.But the fix is easy:
Not recommended: Synchronous "Ajax" calls
As I mentioned, some(!) asynchronous operations have synchronous counterparts. I don't advocate their use, but for completeness' sake, here is how you would perform a synchronous call:
Without jQuery
If you directly use a
XMLHttpRequest
object, passfalse
as third argument to.open
.jQuery
If you use jQuery, you can set the
async
option tofalse
. Note that this option is deprecated since jQuery 1.8.You can then either still use a
success
callback or access theresponseText
property of the jqXHR object:If you use any other jQuery Ajax method, such as
$.get
,$.getJSON
, etc., you have to change it to$.ajax
(since you can only pass configuration parameters to$.ajax
).Heads up! It is not possible to make a synchronous JSONP request. JSONP by its very nature is always asynchronous (one more reason to not even consider this option).
如果您不是在您的代码中使用jQuery,则此答案是为您的,
您的代码应该与此相似:
felix kling做得很好工作为使用jQuery for Ajax的人们写答案,但我决定为不这样做的人提供替代方案。
(注意,对于使用新的
fetch> fetch
api api,Angular或Promise的人,我在下面添加了另一个答案)您面临的内容
是其他答案中“解释问题的解释”的简短摘要,如果您不确定阅读本文后,请阅读此内容。
Ajax中的 a 代表异步。这意味着发送请求(或更确切地说是接收响应)是从正常执行流中取出的。在您的示例中, 立即返回,下一个语句,
返回结果;
,在传递给您的函数之前执行成功
甚至被调用。这意味着当您返回时,您定义的侦听器尚未执行,这意味着您返回的值尚未定义。
这是一个简单的类比:
(fiddle)
a 返回的值是
未定义的
因为a = 5
零件尚未执行。 Ajax的作用是这样,您在服务器有机会告诉您的浏览器该值是什么之前返回值。解决此问题的一种可能解决方案是代码 ,告诉您的程序完成计算后该怎么办。
这称为 cps 。基本上,我们正在传递
getfive
完成完成后执行的操作,我们告诉代码事件完成时如何反应(例如我们的Ajax调用,或在这种情况下为超时)。用法将是:
它应在屏幕上提醒“ 5”。 (fiddle)。
可能的解决方案
基本上有两种解决方法的方法:
1。同步Ajax-不要做!!
至于同步的Ajax,不要做!总而言之,它将冻结用户的浏览器,直到服务器返回响应并创建非常糟糕的用户体验。这是MDN的另一个简短摘要:
如果您有要这样做,则可以传递标志。
”
https://develover.mozilla.org/en-us/docs/web/web/pai/xmlhttprequest/synchronous_and_ashronous_ashronous_requests#synchronous_requests#synchonchronous_request_request_request 您的功能接受回调。在示例代码
foo
中可以接受回调。当foo
完成时,我们将告诉我们的代码如何 react 。因此:
变为:
在这里我们传递了一个匿名函数,但是我们可以很容易地传递对现有功能的引用,使其看起来像:
有关如何完成此类回调设计的更多详细信息,请检查Felix的答案。
现在,让我们定义foo本身以相应地行动
(小提琴)
我们现在已经使我们的 foo 功能接受AJAX成功完成时运行的操作。我们可以通过检查响应状态是否不是200并相应地行动(创建失败处理程序等),以进一步扩展这一点。实际上,它正在解决我们的问题。
如果您仍然很难理解这一点,阅读AJAX启动启动指南< /a>在MDN。
If you're not using jQuery in your code, this answer is for you
Your code should be something along the lines of this:
Felix Kling did a fine job writing an answer for people using jQuery for AJAX, but I've decided to provide an alternative for people who aren't.
(Note, for those using the new
fetch
API, Angular or promises I've added another answer below)What you're facing
This is a short summary of "Explanation of the problem" from the other answer, if you're not sure after reading this, read that.
The A in AJAX stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example,
.send
returns immediately and the next statement,return result;
, is executed before the function you passed assuccess
callback was even called.This means when you're returning, the listener you've defined did not execute yet, which means the value you're returning has not been defined.
Here is a simple analogy:
(Fiddle)
The value of
a
returned isundefined
since thea=5
part has not executed yet. AJAX acts like this, you're returning the value before the server got the chance to tell your browser what that value is.One possible solution to this problem is to code re-actively , telling your program what to do when the calculation completed.
This is called CPS. Basically, we're passing
getFive
an action to perform when it completes, we're telling our code how to react when an event completes (like our AJAX call, or in this case the timeout).Usage would be:
Which should alert "5" to the screen. (Fiddle).
Possible solutions
There are basically two ways how to solve this:
1. Synchronous AJAX - Don't do it!!
As for synchronous AJAX, don't do it! Felix's answer raises some compelling arguments about why it's a bad idea. To sum it up, it'll freeze the user's browser until the server returns the response and create a very bad user experience. Here is another short summary taken from MDN on why:
If you have to do it, you can pass a flag. Here is how:
2. Restructure code
Let your function accept a callback. In the example code
foo
can be made to accept a callback. We'll be telling our code how to react whenfoo
completes.So:
Becomes:
Here we passed an anonymous function, but we could just as easily pass a reference to an existing function, making it look like:
For more details on how this sort of callback design is done, check Felix's answer.
Now, let's define foo itself to act accordingly
(fiddle)
We have now made our foo function accept an action to run when the AJAX completes successfully. We can extend this further by checking if the response status is not 200 and acting accordingly (create a fail handler and such). Effectively it is solving our issue.
If you're still having a hard time understanding this, read the AJAX getting started guide at MDN.
xmlhtttprequest 2 2 href =“ https://stackoverflow.com/a/16825593/19068”> benjamin gruenbaum and )
如果您不使用jQuery并想要一个很好的短片我建议在现代浏览器和移动浏览器中使用的XMLHTTPREQUEST 2,我建议以这种方式使用它:
如您所见:
有两种方法可以获取此AJAX调用的响应(三个使用XMLHTTPREQUEST var name):
最简单:
您
bind()
对类的回调:
或者,如果出于某种原因, 以上是更好的匿名函数总是一个问题):
没什么更简单的。
现在,有些人可能会说最好使用onreadystatechange甚至xmlhttprequest变量名称。那是错误的。
查看 xmlhttprequest高级功能。
它支持所有 *现代浏览器。自从创建XMLHTTPREQUEST 2以来,我可以确认使用这种方法。在我使用的任何浏览器中,我从来没有任何类型的问题。
仅当您想在状态2上获取标题时才有用。
使用
xmlhttprequest
变量名称是另一个大错误,因为您需要在Onload/oreadystatechange封闭中执行回调,否则您又丢失了它。现在,如果您想要使用 post 和formdata,您可以轻松地扩展此信息功能:
再次...这是一个非常短的功能,但是它确实 get 和post。
用法的示例:
或传递完整的表单元素(
document.getElementsbytagname('form')[0]
):或设置一些自定义值:
如您所见,我没有实现同步。这是一件坏事。
话虽如此...为什么我们不这样做?
如评论中所述,使用错误&amp; amp;同步确实打破了答案的重点。正确使用Ajax是哪种简短的方法?
错误处理程序
在上面的脚本中,您有一个静态定义的错误处理程序,因此不会损害该功能。错误处理程序也可以用于其他功能。
但是要出现错误,唯一的方法是写一个错误的URL,在这种情况下,每个浏览器都会引发错误。
错误处理程序可能会有用
如果您设置自定义标题,将响应类型设置为BLOB数组缓冲区,或其他...即使您将“ PostApaPap”作为方法设置为方法,则
。即使您将“ FDGGDGILFDGHFLDJ”作为FormData传递,也不会出错。
在第一种情况下,该错误位于
displayajax()
下的this.statustext
下的错误中,AS方法不允许
。在第二种情况下,它只是起作用。如果您传递了正确的帖子数据,则必须检查服务器端。
不允许的跨域自动抛出错误。
在错误响应中,没有任何错误代码。
只有
this.type
设置为 error 。如果您对错误没有任何控制权,为什么还要添加错误处理程序?
大多数错误都在回调函数
displayajax()
中返回。因此:如果您能够正确复制和粘贴URL,则无需进行错误检查。 ;)
ps:作为第一个测试,我写了x('x',displayajax)...,它完全得到了响应... ???因此,我检查了HTML所在的文件夹,并且有一个名为“ X.xml”的文件。因此,即使您忘记了文件的扩展名xmlhttprequest 2也会找到它。我大声笑
读取文件同步
不要那样做。
如果要阻止浏览器一段时间,请加载一个不错的大
.txt
文件同步。现在,您可以做
其他方法可以以非同步方式进行此操作。 是的,使用Settimeout循环...但是认真吗
?
( 您始终加载相同的XML/JSON或仅需要一个功能。在这种情况下,请修改Ajax功能,然后用特殊功能替换B。
以上功能供基本使用。
如果要扩展 功能...
是的,可以。
我使用了很多API,并且我集成到每个HTML页面中的第一个功能之一是此答案中的第一个AJAX函数,只有获取...
但是您可以使用XMLHTTTPREQUEST 2:我做了很多事情:
我做了一个下载Manager(使用简历,FileReader和Filesystem在两侧使用范围),使用Canvas的各种图像转移器转换器,填充Web SQL数据库,带有base64Images,很多更多...
但是在这些情况下,您应该仅出于此目的创建一个函数...有时您需要一个斑点或数组缓冲区,您可以设置标题,超越模拟物,还有很多...
但是这里的问题是如何返回Ajax响应的方法...(我添加了一种简单的方法。)
XMLHttpRequest 2 (first of all, read the answers from Benjamin Gruenbaum and Felix Kling)
If you don't use jQuery and want a nice short XMLHttpRequest 2 which works in modern browsers and also in mobile browsers, I suggest using it this way:
As you can see:
There are two ways to get the response of this Ajax call (three using the XMLHttpRequest var name):
The simplest:
Or if for some reason you
bind()
the callback to a class:Example:
Or (the above one is better anonymous functions are always a problem):
Nothing easier.
Now some people will probably say that it's better to use onreadystatechange or even the XMLHttpRequest variable name. That's wrong.
Check out XMLHttpRequest advanced features.
It supported all *modern browsers. And I can confirm as I have been using this approach since XMLHttpRequest 2 was created. I never had any type of problem in any browsers I used.
onreadystatechange is only useful if you want to get the headers on state 2.
Using the
XMLHttpRequest
variable name is another big error as you need to execute the callback inside the onload/oreadystatechange closures, or else you lost it.Now if you want something more complex using POST and FormData you can easily extend this function:
Again ... it's a very short function, but it does GET and POST.
Examples of usage:
Or pass a full form element (
document.getElementsByTagName('form')[0]
):Or set some custom values:
As you can see, I didn't implement sync... it's a bad thing.
Having said that ... why don't we do it the easy way?
As mentioned in the comment, the use of error && synchronous does completely break the point of the answer. Which is a nice short way to use Ajax properly?
Error handler
In the above script, you have an error handler which is statically defined, so it does not compromise the function. The error handler can be used for other functions too.
But to get out an error, the only way is to write a wrong URL in which case every browser throws an error.
Error handlers may maybe useful if you set custom headers, set the responseType to blob array buffer, or whatever...
Even if you pass 'POSTAPAPAP' as the method it won't throw an error.
Even if you pass 'fdggdgilfdghfldj' as formdata it won't throw an error.
In the first case, the error is inside the
displayAjax()
underthis.statusText
asMethod not Allowed
.In the second case, it simply works. You have to check on the server side if you passed the right post data.
Cross-domain not allowed throws an error automatically.
In the error response, there aren't any error codes.
There is only the
this.type
which is set to error.Why add an error handler if you don't have any control over errors?
Most of the errors are returned inside this in the callback function
displayAjax()
.So: There isn't any need for error checks if you're able to copy and paste the URL properly. ;)
PS: As the first test I wrote x('x', displayAjax)..., and it totally got a response...??? So I checked the folder where the HTML is located, and there was a file called 'x.xml'. So even if you forget the extension of your file XMLHttpRequest 2 WILL FIND IT. I LOL'd
Read a file synchronous
Don't do that.
If you want to block the browser for a while load a nice big
.txt
file synchronous.Now you can do
There is no other way to do this in a non-asynchronous way. (Yeah, with setTimeout loop... but seriously?)
Another point is... if you work with APIs or just your own list's files or whatever you always use different functions for each request...
Only if you have a page where you load always the same XML/JSON or whatever you need only one function. In that case, modify a little the Ajax function and replace b with your special function.
The functions above are for basic use.
If you want to extend the function...
Yes, you can.
I'm using a lot of APIs and one of the first functions I integrate into every HTML page is the first Ajax function in this answer, with GET only...
But you can do a lot of stuff with XMLHttpRequest 2:
I made a download manager (using ranges on both sides with resume, filereader, and filesystem), various image resizers converters using canvas, populate web SQL databases with base64images and much more...
But in these cases you should create a function only for that purpose... sometimes you need a blob, or array buffers, you can set headers, override mimetype and there is a lot more...
But the question here is how to return an Ajax response... (I added an easy way.)
如果您使用的是承诺,则此答案适合您。
这意味着Angularjs,jQuery(带延迟),本机 xhr“> xhr”> xhr href =“ https://en.wikipedia.org/wiki/ember.js” rel =“ noreferrer”> ember.js , backbone.js 保存或任何 node.js 返回承诺的库。
您的代码应该与此相似:
Felix Kling做得很好为使用jQuery和回调的人写答案。我有一个本地XHR的答案。这个答案是用于对前端或后端上承诺的一般用法。
核心问题
在浏览器和服务器上使用node.js/io.js在服务器中的JavaScript并发模型是 asynchronous 和反应性。
每当您调用返回诺言的方法时,
然后
处理程序始终异步执行 - 也就是说, 下方的代码不是在中。然后
处理程序。这意味着,当您返回
处理程序尚未执行。反过来,这意味着您要返回的值尚未设置为正确的值。
数据
这是一个简单的类比:
data
的值是不确定的
,因为data = 5
零件尚未执行。它可能会在一秒钟内执行,但是到那时,它与返回的值无关。由于该操作尚未发生(AJAX,服务器调用,I/O和计时器),您在请求有机会告诉您的代码是什么值之前返回值。
解决此问题的一种可能解决方案是代码 ,告诉您的程序完成计算后该怎么办。承诺通过本质上是时间(时间敏感)来积极实现这一目标。
快速回顾承诺的承诺
是随时间的价值。承诺有状态。他们从没有价值的待审开始,可以安定下来:
诺言只能改变状态 之后,它将永远保持在同一状态。您可以将
附加
处理程序附加,以承诺提取其价值并处理错误。然后
处理程序允许 chaning> chaning> chaning 。承诺由使用返回它们。例如,更现代的AJAX替换Fetch
或jQuery的$。get
返回承诺。当我们调用
。如果我们回报另一个诺言,我们会得到令人惊奇的事情,但让我们握住马匹。
有了承诺,
让我们看看如何通过承诺解决上述问题。首先,让我们通过使用承诺构造函数用于创建延迟功能:
现在,我们转换的settiemoutout 使用诺言,我们可以使用<代码>然后使其计数:
基本上,而不是返回 value ,我们由于并发模型而无法做,而是我们返回a wrapper ,以获取我们可以 unwrap <的值/em>带有<代码>然后。就像一个框,您可以使用
然后
打开。在原始API调用中应用此
信息相同,您可以:
这样也可以。我们已经了解到,我们无法从已经异步的调用中返回值,但是我们可以使用诺言并将其链接来执行处理。现在,我们知道如何从异步呼叫中返回响应。
ES2015(ES6)
ES6引入是可以在中间返回然后恢复其点的功能。例如,这通常对于序列很有用,例如:
是一个函数,该函数可以通过序列返回序列
1,2,3,3,3,3,....
可以迭代。尽管这本身很有趣,并为很多可能性打开了空间,但有一个特别的案例。如果我们要产生的序列是一系列动作,而不是数字 - 我们可以在恢复函数之前等待动作并等待该功能。因此,我们需要一个 future 值的序列,而不是数字序列,也就是说:承诺。
这有点棘手,但非常有力的技巧让我们以同步的方式编写异步代码。有几个“跑步者”为您做到这一点。写一条是几行代码,但它超出了该答案的范围。我将在此处使用Bluebird的
Promise.coroutine
,但是还有其他包装器,例如co </code>或
q.async
。此方法返回了一个承诺本身,我们可以从其他coroutines中消费。例如:
ES7中的ES2016(ES7)
,这是进一步标准化的。现在有几个建议,但是在所有建议中,您都可以
等待
承诺。这只是上述ES6提案的“糖”(较好的语法),通过添加async
和等待
关键字。进行上面的示例:它仍然返回承诺同样的示例:)
If you're using promises, this answer is for you.
This means AngularJS, jQuery (with deferred), native XHR's replacement (fetch), Ember.js, Backbone.js's save or any Node.js library that returns promises.
Your code should be something along the lines of this:
Felix Kling did a fine job writing an answer for people using jQuery with callbacks for Ajax. I have an answer for native XHR. This answer is for generic usage of promises either on the frontend or backend.
The core issue
The JavaScript concurrency model in the browser and on the server with Node.js/io.js is asynchronous and reactive.
Whenever you call a method that returns a promise, the
then
handlers are always executed asynchronously - that is, after the code below them that is not in a.then
handler.This means when you're returning
data
thethen
handler you've defined did not execute yet. This in turn means that the value you're returning has not been set to the correct value in time.Here is a simple analogy for the issue:
The value of
data
isundefined
since thedata = 5
part has not executed yet. It will likely execute in a second, but by that time it is irrelevant to the returned value.Since the operation did not happen yet (Ajax, server call, I/O, and timer) you're returning the value before the request got the chance to tell your code what that value is.
One possible solution to this problem is to code re-actively, telling your program what to do when the calculation completed. Promises actively enable this by being temporal (time-sensitive) in nature.
Quick recap on promises
A Promise is a value over time. Promises have state. They start as pending with no value and can settle to:
A promise can only change states once after which it will always stay at the same state forever. You can attach
then
handlers to promises to extract their value and handle errors.then
handlers allow chaining of calls. Promises are created by using APIs that return them. For example, the more modern Ajax replacementfetch
or jQuery's$.get
return promises.When we call
.then
on a promise and return something from it - we get a promise for the processed value. If we return another promise we'll get amazing things, but let's hold our horses.With promises
Let's see how we can solve the above issue with promises. First, let's demonstrate our understanding of promise states from above by using the Promise constructor for creating a delay function:
Now, after we converted setTimeout to use promises, we can use
then
to make it count:Basically, instead of returning a value which we can't do because of the concurrency model - we're returning a wrapper for a value that we can unwrap with
then
. It's like a box you can open withthen
.Applying this
This stands the same for your original API call, you can:
So this works just as well. We've learned we can't return values from already asynchronous calls, but we can use promises and chain them to perform processing. We now know how to return the response from an asynchronous call.
ES2015 (ES6)
ES6 introduces generators which are functions that can return in the middle and then resume the point they were at. This is typically useful for sequences, for example:
Is a function that returns an iterator over the sequence
1,2,3,3,3,3,....
which can be iterated. While this is interesting on its own and opens room for a lot of possibility, there is one particular interesting case.If the sequence we're producing is a sequence of actions rather than numbers - we can pause the function whenever an action is yielded and wait for it before we resume the function. So instead of a sequence of numbers, we need a sequence of future values - that is: promises.
This somewhat a tricky, but very powerful trick let’s us write asynchronous code in a synchronous manner. There are several "runners" that do this for you. Writing one is a short few lines of code, but it is beyond the scope of this answer. I'll be using Bluebird's
Promise.coroutine
here, but there are other wrappers likeco
orQ.async
.This method returns a promise itself, which we can consume from other coroutines. For example:
ES2016 (ES7)
In ES7, this is further standardized. There are several proposals right now, but in all of them you can
await
promise. This is just "sugar" (nicer syntax) for the ES6 proposal above by adding theasync
andawait
keywords. Making the above example:It still returns a promise just the same :)
您错误地使用了Ajax。这个想法不是让它返回任何内容,而是将数据移交给处理数据的名为“回调函数”。
也就是说:
返回提交处理程序中的任何内容都不会做任何事情。取而代之的是,您必须移交数据,或者直接在成功函数中使用您想做的事情。
You are using Ajax incorrectly. The idea is not to have it return anything, but instead hand off the data to something called a callback function, which handles the data.
That is:
Returning anything in the submit handler will not do anything. You must instead either hand off the data, or do what you want with it directly inside the success function.
我会以可怕的手绘漫画回答。第二张图像是
在代码示例中的原因。
结果
是I will answer with a horrible-looking, hand-drawn comic. The second image is the reason why
result
isundefined
in your code example.最简单的解决方案是创建JavaScript函数,并为AJAX
Success
回调称其为调用。The simplest solution is to create a JavaScript function and call it for the Ajax
success
callback.这里的大多数答案给出了一个有用的建议,何时进行单个异步操作,但是有时候,当您需要在数组或其他类似列表的结构中为每个每个条目进行异步操作时,这会出现。诱惑是这样做:
示例:
不起作用的原因是
dosomethingsasync
的回调尚未在尝试使用结果时运行。因此,如果您有一个数组(或某种形式的列表),并且想对每个条目进行异步操作,则有两个选项:并行执行操作(重叠)或串联(一个接一个地,顺序)。
并行
您可以启动所有这些,并跟踪您期望多少回调,然后在收到许多回调时使用结果:
示例:
(我们可以消除
期望
,只使用result.length === thearray.length
,但这使我们对thearray的可能性开放
在呼叫未偿的时候更改...)请注意我们如何使用
index
forforeach
将结果保存在结果中
与即使结果取出订单,它也与之相关(因为异步调用不一定要以启动的顺序完成)。但是,如果您需要返回 这些结果来自函数呢?正如其他答案所指出的,您不能;您必须接受函数接受并致电回调(或返回a 承诺)。这是回调版本:
示例:
或以下是返回
Promise
的版本:当然,如果
dosomethingsasync
传递了我们的错误,我们将使用recept> recood
拒绝当我们遇到错误时承诺。)示例:
制作包装器,然后执行以下...)
(或者,或者,您可以为返回承诺的
:
dosomethingsasync
a Promise ,您可以使用,您可以使用“ noreferrer”>Promise.promise.all
如果您知道
dosomethingasync
将忽略第二个和第三个参数,则可以将其直接传递给MAP
(MAP
用三个参数调用其回调,但大多数人最多只使用第一个参数):示例:示例:
请注意,
Promise.All
通过所有诺言的结果来解决其承诺,当他们全部解决时,您给予的承诺,或者在 first of时拒绝其承诺您给予的承诺拒绝。系列
假设您不希望操作并行?如果您想一个接一个地运行它们,则需要等待每个操作完成下一个操作。这是一个可以执行此操作并调用结果的函数的示例:
(由于我们正在串联进行工作,因此我们可以使用
results.push(result)(result)
,因为我们知道我们不会在上面的订单中获得结果。 )示例:
(或者,再次为
dosomethingsasync
构建一个包装器,可以给您一个承诺,并做下面...)如果
Dosomething> ,如果您可以使用ES2017+语法(也许与 babel ),您可以使用
async
函数 with for/code> < /a>和等待
等待href = “
If you can't use ES2017+ syntax (yet), you can use a variation on the
示例:
...与:
示例:
Most of the answers here give useful suggestions for when you have a single async operation, but sometimes, this comes up when you need to do an asynchronous operation for each entry in an array or other list-like structure. The temptation is to do this:
Example:
The reason that doesn't work is that the callbacks from
doSomethingAsync
haven't run yet by the time you're trying to use the results.So, if you have an array (or list of some kind) and want to do async operations for each entry, you have two options: Do the operations in parallel (overlapping), or in series (one after another in sequence).
Parallel
You can start all of them and keep track of how many callbacks you're expecting, and then use the results when you've gotten that many callbacks:
Example:
(We could do away with
expecting
and just useresults.length === theArray.length
, but that leaves us open to the possibility thattheArray
is changed while the calls are outstanding...)Notice how we use the
index
fromforEach
to save the result inresults
in the same position as the entry it relates to, even if the results arrive out of order (since async calls don't necessarily complete in the order in which they were started).But what if you need to return those results from a function? As the other answers have pointed out, you can't; you have to have your function accept and call a callback (or return a Promise). Here's a callback version:
Example:
Or here's a version returning a
Promise
instead:Of course, if
doSomethingAsync
passed us errors, we'd usereject
to reject the promise when we got an error.)Example:
(Or alternately, you could make a wrapper for
doSomethingAsync
that returns a promise, and then do the below...)If
doSomethingAsync
gives you a Promise, you can usePromise.all
:If you know that
doSomethingAsync
will ignore a second and third argument, you can just pass it directly tomap
(map
calls its callback with three arguments, but most people only use the first most of the time):Example:
Note that
Promise.all
resolves its promise with an array of the results of all of the promises you give it when they are all resolved, or rejects its promise when the first of the promises you give it rejects.Series
Suppose you don't want the operations to be in parallel? If you want to run them one after another, you need to wait for each operation to complete before you start the next. Here's an example of a function that does that and calls a callback with the result:
(Since we're doing the work in series, we can just use
results.push(result)
since we know we won't get results out of order. In the above we could have usedresults[index] = result;
, but in some of the following examples we don't have an index to use.)Example:
(Or, again, build a wrapper for
doSomethingAsync
that gives you a promise and do the below...)If
doSomethingAsync
gives you a Promise, if you can use ES2017+ syntax (perhaps with a transpiler like Babel), you can use anasync
function withfor-of
andawait
:Example:
If you can't use ES2017+ syntax (yet), you can use a variation on the "Promise reduce" pattern (this is more complex than the usual Promise reduce because we're not passing the result from one into the next, but instead gathering up their results in an array):
Example:
...which is less cumbersome with ES2015+ arrow functions:
Example:
使用
个人“ 。
在这里
您可以找到一个不错的解释在这里也是如此。
在
Angular 2及以后
在Angular 2中查看以下示例,但其建议用Angular 2使用
可
观察的 。 href =“ https://angular-2-training-book.rangle.io/handout/http/requests_as_promises.html” rel =“ noreferrer”>原始在此处发布。但是Typescript不支持本机ES6承诺,如果您想使用它,您可能需要插件为此。
此外,这是承诺规格。
Angular 1
People who are using AngularJS, can handle this situation using promises.
Here it says,
You can find a nice explanation here also.
An example found in documentation mentioned below.
Angular 2 and later
In Angular 2 with look at the following example, but its recommended to use observables with Angular 2.
You can consume that in this way,
See the original post here. But TypeScript does not support native ES6 Promises, if you want to use it, you might need plugin for that.
Additionally, here is the promises specification.
请查看此示例:
,您可以看到
getJoke
是 返回解决解决 Promise 返回res.data.value
)。因此,您要等到 $ http.get 请求完成,然后执行 console.log(res.joke)(作为正常的异步流)。这是Plnkr:
ES6方式(异步 - 等待)
Have a look at this example:
As you can see
getJoke
is returning a resolved promise (it is resolved when returningres.data.value
). So you wait until the $http.get request is completed and then console.log(res.joke) is executed (as a normal asynchronous flow).This is the plnkr:
http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/
ES6 way (async - await)
这是双向数据绑定或商店概念在许多新的JavaScript框架中使用的地方之一,这对您来说非常有用...
因此,如果您使用< a href =“ https://en.wikipedia.org/wiki/angular_(web_framework)” rel =“ noreferrer”> angular href =“ https://en.wikipedia.org/wiki/wiki/react_(web_framework)” rel =“ noreferrer”> react 或任何其他有双向数据绑定或存储概念的其他框架,此问题是简单地为您修复,因此,简单地说,您的结果是
在第一阶段
,因此您有result =未定义的
在收到数据之前,一旦获得结果,它将被更新并分配给新值AJAX调用的响应...但是如何在纯JavaScript或例如,正如您在这个问题中提出的那样?
您可以使用回调,承诺并最近可观察到为您处理。例如,在承诺中,我们具有一些功能,例如
success()
或then()
,当您的数据准备就绪时将执行。可观察到的回调或 subscribe 函数相同。例如,在您正在使用jQuery的情况下,您可以做类似的事情:
有关更多信息,研究承诺和观察物是做这种异步工作的新方法。
This is one of the places which two-way data binding or store concept that's used in many new JavaScript frameworks will work great for you...
So if you are using Angular, React, or any other frameworks which do two-way data binding or store concept, this issue is simply fixed for you, so in easy words, your result is
undefined
at the first stage, so you have gotresult = undefined
before you receive the data, then as soon as you get the result, it will be updated and get assigned to the new value which response of your Ajax call...But how you can do it in pure JavaScript or jQuery for example as you asked in this question?
You can use a callback, promise and recently observable to handle it for you. For example, in promises we have some function like
success()
orthen()
which will be executed when your data is ready for you. The same with callback or the subscribe function on an observable.For example, in your case which you are using jQuery, you can do something like this:
For more information, study promises and observables which are newer ways to do this async stuff.
这是我们在JavaScript的“奥秘”挣扎时面临的一个非常普遍的问题。让我尝试今天揭开这个谜。
让我们从一个简单的JavaScript函数开始:
这是一个简单的同步函数调用(在下一个代码的每行都“完成其作业”的“完成”),结果与预期的结果相同。
现在,让我们通过在函数中引入一点延迟来添加一些扭曲,以使所有代码都不是“完成”的。因此,它将模仿该功能的异步行为:
因此您就去了;延迟刚刚打破了我们期望的功能!但是到底发生了什么?好吧,如果您查看代码,这实际上是合乎逻辑的。
函数
foo()
,在执行后,返回什么都没有(因此返回的值是undefined
),但它确实启动了一个计时器,该计时器在1秒钟后执行函数以返回'哇。但是,如您所见,分配给bar的值是Foo()的立即返回的内容,即,即undefined
。那么,我们如何解决这个问题
?
承诺实际上是关于它的含义:这意味着功能可以确保您提供将来的任何输出。因此,让我们在上面的小问题上查看它的行动:
因此,摘要是 - 处理类似基于AJAX的呼叫等异步函数,您可以使用承诺来
resolve> resolve
该值(哪个值(您打算返回)。因此,简而言之,您解决值,而不是返回,在异步函数中。除了使用
然后/catch
与Promises合作之外,更新(ASYNC/等待的承诺)除了使用
之外,还有另一种方法。这个想法是识别异步函数,然后等待承诺在移至下一行代码之前解决。它仍然只是引擎盖下的
承诺
,但采用不同的句法方法。为了使事情变得更清晰,您可以在下面找到一个比较:然后/捕获版本:
async/等待版本:
It's a very common issue we face while struggling with the 'mysteries' of JavaScript. Let me try demystifying this mystery today.
Let's start with a simple JavaScript function:
That's a simple synchronous function call (where each line of code is 'finished with its job' before the next one in sequence), and the result is same as expected.
Now let's add a bit of twist, by introducing a little delay in our function, so that all lines of code are not 'finished' in sequence. Thus, it will emulate the asynchronous behavior of the function:
So there you go; that delay just broke the functionality we expected! But what exactly happened? Well, it's actually pretty logical if you look at the code.
The function
foo()
, upon execution, returns nothing (thus returned value isundefined
), but it does start a timer, which executes a function after 1 second to return 'wohoo'. But as you can see, the value that's assigned to bar is the immediately returned stuff from foo(), which is nothing, i.e., justundefined
.So, how do we tackle this issue?
Let's ask our function for a promise.
Promise is really about what it means: it means that the function guarantees you to provide with any output it gets in future. So let's see it in action for our little problem above:
Thus, the summary is - to tackle the asynchronous functions like Ajax-based calls, etc., you can use a promise to
resolve
the value (which you intend to return). Thus, in short you resolve value instead of returning, in asynchronous functions.UPDATE (Promises with async/await)
Apart from using
then/catch
to work with promises, there exists one more approach. The idea is to recognize an asynchronous function and then wait for the promises to resolve, before moving to the next line of code. It's still just thepromises
under the hood, but with a different syntactical approach. To make things clearer, you can find a comparison below:then/catch version:
async/await version:
从异步函数返回值的另一种方法是传递将从异步函数中存储结果的对象。
这是一个相同的示例:
我正在使用
结果
对象在异步操作期间存储该值。这允许结果即使在异步工作后也可以使用。我经常使用这种方法。我很想知道这种方法的效果如何,其中涉及连续模块的结果对结果进行接线。
Another approach to return a value from an asynchronous function, is to pass in an object that will store the result from the asynchronous function.
Here is an example of the same:
I am using the
result
object to store the value during the asynchronous operation. This allows the result be available even after the asynchronous job.I use this approach a lot. I would be interested to know how well this approach works where wiring the result back through consecutive modules is involved.
尽管承诺和回调在许多情况下都可以正常工作,但后方表达出类似的内容是一种痛苦:
您最终会通过
async1
;检查name
是否未定义,并相应地致电回调。虽然好的在小例子中,当您有很多类似的情况和涉及错误处理时,它会很烦人。
纤维
有助于解决问题。您可以检查项目此处。
While promises and callbacks work fine in many situations, it is a pain in the rear to express something like:
You'd end up going through
async1
; check ifname
is undefined or not and call the callback accordingly.While it is okay in small examples it gets annoying when you have a lot of similar cases and error handling involved.
Fibers
helps in solving the issue.You can checkout the project here.
我编写的以下示例显示了如何
这个工作示例是独立的。它将定义一个简单的请求对象,该对象使用窗口
xmlhttprequest
对象进行呼叫。它将定义一个简单的功能,以等待一堆诺言要完成。语境。该示例是查询 spotify web api 端点以搜索
播放列表
给定的查询字符串的对象:对于每个项目,一个新的承诺将发射一个块 -
executionBlock
,解析结果,根据结果数组安排一组新的承诺,即Spotifyuser
对象的列表,并在executionProfileBlock
ynchronChronical中执行新的HTTP调用。然后,您可以看到一个嵌套的承诺结构,该结构使您可以产生多个和完全异步的嵌套HTTP调用,并通过
Promise.all
从每个呼叫的每个子集中加入每个子集的结果。注意
最近的Spotify
搜索
API需要在请求标题中指定访问令牌:因此,您要运行以下示例,需要将访问令牌放在请求标题中:
我已经广泛讨论了此解决方案在这里。
The following example I have written shows how to
This working example is self-contained. It will define a simple request object that uses the window
XMLHttpRequest
object to make calls. It will define a simple function to wait for a bunch of promises to be completed.Context. The example is querying the Spotify Web API endpoint in order to search for
playlist
objects for a given set of query strings:For each item, a new Promise will fire a block -
ExecutionBlock
, parse the result, schedule a new set of promises based on the result array, that is a list of Spotifyuser
objects and execute the new HTTP call within theExecutionProfileBlock
asynchronously.You can then see a nested Promise structure, that lets you spawn multiple and completely asynchronous nested HTTP calls, and join the results from each subset of calls through
Promise.all
.NOTE
Recent Spotify
search
APIs will require an access token to be specified in the request headers:So, you to run the following example you need to put your access token in the request headers:
I have extensively discussed this solution here.
简短的答案是,您必须实现这样的回调:
The short answer is, you have to implement a callback like this:
浏览器可以分为三个部分:
事件循环
Web API
事件队列
活动循环将永远运行,即,有点无限循环。事件队列是在某些事件上推动所有功能的地方(例如:单击)。
这是一对一地从队列中进行的,并将其放入事件循环中,该循环执行此功能,并在执行第一个功能后为下一个功能做准备。这意味着在事件循环中执行一个函数之前,执行一个函数才能启动。
现在,让我们认为我们在队列中推动了两个功能。一种是从服务器中获取数据,另一个是利用该数据。我们首先在队列中推动了serverRequest()函数,然后在fultiedata()函数中推出。在事件循环中,ServerRequest函数会进行,并致电服务器,因为我们永远不知道从服务器获取数据需要多少时间,因此此过程有望花费时间,因此我们忙于活动循环,从而悬挂了页面。
这就是Web API担任角色的地方。它从事件循环中获取此功能,并处理服务器,使事件循环免费,因此我们可以从队列执行下一个功能。
队列中的下一个功能是lutiedata(),它在循环中进行,但是由于没有可用的数据,它一直浪费和执行下一个功能一直持续到队列结束为止。 (这称为异步调用,即,我们可以做其他事情,直到获取数据为止。)
让我们假设我们的ServerRequest()函数在代码中具有返回语句。当我们从服务器Web API获取数据时,它将在队列结束时将其推入队列。
当它在队列结束时被推开时,我们无法利用其数据,因为我们队列中没有任何功能可以利用此数据。 因此,不可能从异步调用中返回某些东西。
因此,解决方案是 callback 或 promise 。
我们提供了我们的功能(使用从服务器)到调用服务器的函数。
在我的代码中,它被称为:
javascript.info callback
The browser can be divided into three parts:
Event Loop
Web API
Event Queue
The event loop runs for forever, i.e., kind of an infinite loop. The event queue is where all your functions are pushed on some event (example: click).
This is one by one carried out of queue and put into the event loop which executes this function and prepares itself for the next one after the first one is executed. This means execution of one function doesn't start until the function before it in the queue is executed in the event loop.
Now let us think we pushed two functions in a queue. One is for getting a data from the server and another utilises that data. We pushed the serverRequest() function in the queue first and then the utiliseData() function. The serverRequest function goes in the event loop and makes a call to server as we never know how much time it will take to get data from server, so this process is expected to take time and so we busy our event loop thus hanging our page.
That's where Web API come into the role. It takes this function from the event loop and deals with the server making the event loop free, so that we can execute the next function from the queue.
The next function in the queue is utiliseData() which goes in the loop, but because of no data available, it goes to waste and execution of the next function continues until the end of the queue. (This is called Async calling, i.e., we can do something else until we get data.)
Let us suppose our serverRequest() function had a return statement in code. When we get back data from the server Web API, it will push it in the queue at the end of queue.
As it gets pushed at the end of the queue, we cannot utilise its data as there isn't any function left in our queue to utilise this data. Thus it is not possible to return something from the async call.
Thus the solution to this is callback or promise.
We give our function (function utilising data returned from the server) to a function calling the server.
In my code it is called as:
JavaScript.info callback
2017答案:您现在可以在当前的每个浏览器中完全做您想要的操作, noreferrer”> node.js
这很简单:
async代码的版本:
在所有当前浏览器和node.js 8 中都支持等待
2017 answer: you can now do exactly what you want in every current browser and Node.js
This is quite simple:
Here's a working version of your code:
await is supported in all current browsers and Node.js 8
您可以使用此自定义库(用承诺书写)进行远程调用。
简单用法示例:
You can use this custom library (written using Promise) to make a remote call.
Simple usage example:
另一个解决方案是通过顺序执行器执行代码 nsynjs 。
如果基础函数受到承诺,则
NSYNJS将依次评估所有承诺,并将承诺结果放入
data
属性中:如果基础函数不承诺
步骤1。将函数用回调包装到Nsynjs-Aware Warper包装器(如果它具有合理的版本,您可以跳过此步骤):
步骤2。将同步逻辑放入函数:
步骤3。运行。运行。运行。通过nsynjs以同步方式函数:
nsynjs将评估所有操作员和表达式的逐步,如果某些慢函数的结果为,则暂停执行还没准备好。
更多示例是在这里。
Another solution is to execute code via the sequential executor nsynjs.
If the underlying function is promisified
nsynjs will evaluate all promises sequentially, and put the promise result into the
data
property:If the underlying function is not promisified
Step 1. Wrap the function with a callback into the nsynjs-aware wrapper (if it has a promisified version, you can skip this step):
Step 2. Put synchronous logic into function:
Step 3. Run function in synchronous manner via nsynjs:
Nsynjs will evaluate all operators and expressions step-by-step, pausing execution in case if the result of some slow function is not ready.
More examples are here.
1。对于其他许多人来说,这是第一个绊脚石
,我与异步电话的相遇起初令人困惑。
我不记得细节,但我可能尝试了类似的事情:
whops!
线的输出
console.log('最后,结果:' +结果);
我认为将在另一个输出之前打印出上次。
- 并且它不包含结果:它只是打印
未定义的
。 1怎么会?
一个有用的见解,
我清楚地记得我的第一个 aha (
1. A first stumbling step
As for many others, my encounter with asynchronous calls was puzzling at first.
I don't remember the details, but I may have tried something like:
Whoops!
The output of the line
console.log('Finally, the result: ' + result);
which I thought would be printed last, is printed before the other output!
– And it doesn't contain the result: it just prints
undefined
. 1How come?
A helpful insight
I distinctly remember my first aha (????) moment about asynchronous calls.
It was :
This is true in the example above.
2. Plain JavaScript and a callback function
Luckily, it is possible to write code after the asynchronous call that deals with the response once it has completed.
One alternative is the use of a callback function in a continuation-passing style :
3
Note how the function
asynchronousFunc
isvoid
. It returns nothing.asynchronousFunc
is called with an anonymous callback function,(
asynchronousFunc(function (result) {...});
).This executes the desired actions on the result after the request has completed – when the
responseText
is available.Running the above snippet shows how I will probably not want to write any code after the asynchronous call (such as the line
LAST in the code, but executed FIRST!
).Why? – Because such code will run before the asynchronous call delivers any response data.
Doing so is bound to cause confusion when comparing the code with the output.
3. Promise with
.then()
The
.then()
construct was introduced in the ECMA-262 6th Edition in June 2015.The code below is plain JavaScript, replacing the old-school XMLHttpRequest with Fetch. 4
4. Promise with
async
/await
The
async
/await
construct was introduced in the ECMA-262 8th Edition in June 2017.A word of warning is warranted if you decide to go with the
async
/await
construct.Note in the above snippet how
await
is needed in two places.If forgotten in the first place, there will be no output at all.
If forgotten in the second place, the only output will be
Using async/await:
– nothing else gets printed.Forgetting the
async
prefix of the function is maybe the worst of all – you'll get a"SyntaxError"
– and likely no hint about the missingasync
keyword.All the above examples succinctly convey how asynchronous calls may be used on toyish APIs. 5
References
async
/await
1
Expressed by the asker of the question as they all return
undefined
.2
Here is more on how asynchronous calls may be confusing at first.
3
Like the X in AJAX, the name
XMLHttpRequest
is misleading – it can be used to retrieve any type of data, not just XML.These days, the data format of Web APIs is ubiquitously JSON, not XML.
4
Fetch returns a Promise.
I was surprised to learn that neither XMLHttpRequest nor Fetch are part of the ECMAScript standard.
The reason JavaScript can access them here is that the web browser provides them.
The Fetch Standard and the XMLHttpRequest Standard are both upheld by the Web Hypertext Application Technology Working Group which was formed in June 2004. \
5
You might also be interested in
How can I fetch an array of URLs with Promise.all?.
Ecmascript 6具有“发电机”,可让您轻松地以异步风格进行编程。
要运行上述代码,您要这样做:
如果您需要定位不支持ES6的浏览器,则可以通过babel或closure-compiler运行代码以生成ecmascript 5。
呼叫
... args
在阅读时,被包裹在数组中并破坏,以便模式可以应对具有多个参数的回调。例如,使用 node fs fs :ECMAScript 6 has 'generators' which allow you to easily program in an asynchronous style.
To run the above code you do this:
If you need to target browsers that don't support ES6 you can run the code through Babel or closure-compiler to generate ECMAScript 5.
The callback
...args
are wrapped in an array and destructured when you read them so that the pattern can cope with callbacks that have multiple arguments. For example with node fs:我们发现自己处在一个宇宙中,似乎沿着我们称为“时间”的维度发展。我们并不真正了解几点钟了,但是我们开发了抽象和词汇,让我们推理并谈论它:“过去”,“现在”,“未来”,“之前”,“之后”。
我们构建的计算机系统(又是更多的时间)是一个重要的维度。将来会发生某些事情。然后,在最终发生这些第一件事之后,其他事情需要发生。这是称为“异步性”的基本概念。在我们越来越网络的世界中,异步性最常见的情况是等待某些远程系统响应某些请求。
考虑一个例子。您打电话给牛奶员并点牛奶。到来时,您想把它放入咖啡中。您现在不能将牛奶放入咖啡中,因为它还不在这里。您必须等待它来放入咖啡之前。换句话说,以下内容无法使用:
因为JavaScript无法知道它需要等待
order> order_milk
在执行put_in_coffee 。换句话说,它不知道
order_milk
是异步 - 是直到将来的时间都不会导致牛奶的东西。 JavaScript和其他声明性语言在不等待的情况下执行一个语句。经典的JavaScript方法来解决此问题,利用JavaScript支持函数作为可以通过的一流对象的事实,就是将函数作为参数传递给异步请求,然后在完成后将其调用。将来的某个时候它的任务。那是“回调”方法。看起来像这样:
order_milk
启动,订购牛奶,然后,仅当它到达时,它才会调用put_in_coffee
。这种回调方法的问题在于,它用
返回
污染了函数的正常语义;取而代之的是,函数不得通过调用给定的回调作为参数来报告其结果。同样,在处理更长的事件序列时,这种方法可能会迅速变得笨拙。例如,假设我想等待将牛奶放入咖啡中,然后再进行第三步,即喝咖啡。我最终需要写下这样的东西:我要传递到
put_in_coffee
两个牛奶都要放入其中,还有一旦牛奶执行操作(draind_coffee
)已被放入。此类代码很难编写,阅读和调试。在这种情况下,我们可以在问题中重写:
Enter Prosise
这是“承诺”概念的动机,这是一种特定的价值,代表A future> Future 或异步某种形式的结果。它可以代表已经发生的事情,或者将来会发生,或者可能永远不会发生。承诺具有一种名为
然后
的方法,当您实现承诺所代表的结果时,您将通过该操作执行。对于牛奶和咖啡,我们设计
order_milk
返回到达牛奶的承诺,然后将put_in_coffee
然后如下所示:其中一个优点是,我们可以将它们串在一起以创建未来发生的序列(“链接”):
让我们将承诺应用于您的特定问题。我们将我们的请求逻辑包装在一个函数中,该函数返回承诺:
实际上,我们所做的只是添加
返回
到调用到$。ajax
。这是因为jQuery的$。ajax
已经返回一种有希望的东西。 (实际上,在不详细介绍的情况下,我们希望将此调用包装,以便返回真正的诺言,或者使用$。ajax
的替代方案。)现在,如果我们想加载文件并等待它完成做点事
然后 紧凑型ES6式箭头函数:
async
关键字,但是如果同步和异步,必须以一种方式编写代码,以一种方式编写代码仍然有些不满意。对于同步,我们编写,
但是如果
a
是异步的,则有了我们必须在上面写下的承诺,我们说:“ JavaScript无法知道它需要等待第一个呼叫在执行第二次之前完成。如果有某种方式告诉JavaScript,那不是很好吗?事实证明,存在 -
等待
关键字,在一种特殊类型的函数中使用,称为“ async”函数。此功能是即将推出的eCmascript(es)的一部分,但是它已经在诸如 babel 给定正确的预设。这使我们可以简单地写下您的情况,您将能够写出类似的东西
We find ourselves in a universe which appears to progress along a dimension we call "time". We don't really understand what time is, but we have developed abstractions and vocabulary that let us reason and talk about it: "past", "present", "future", "before", "after".
The computer systems we build--more and more--have time as an important dimension. Certain things are set up to happen in the future. Then other things need to happen after those first things eventually occur. This is the basic notion called "asynchronicity". In our increasingly networked world, the most common case of asynchronicity is waiting for some remote system to respond to some request.
Consider an example. You call the milkman and order some milk. When it comes, you want to put it in your coffee. You can't put the milk in your coffee right now, because it is not here yet. You have to wait for it to come before putting it in your coffee. In other words, the following won't work:
Because JavaScript has no way to know that it needs to wait for
order_milk
to finish before it executesput_in_coffee
. In other words, it does not know thatorder_milk
is asynchronous--is something that is not going to result in milk until some future time. JavaScript, and other declarative languages execute one statement after another without waiting.The classic JavaScript approach to this problem, taking advantage of the fact that JavaScript supports functions as first-class objects which can be passed around, is to pass a function as a parameter to the asynchronous request, which it will then invoke when it has completed its task sometime in the future. That is the "callback" approach. It looks like this:
order_milk
kicks off, orders the milk, then, when and only when it arrives, it invokesput_in_coffee
.The problem with this callback approach is that it pollutes the normal semantics of a function reporting its result with
return
; instead, functions must not reports their results by calling a callback given as a parameter. Also, this approach can rapidly become unwieldy when dealing with longer sequences of events. For example, let's say that I want to wait for the milk to be put in the coffee, and then and only then perform a third step, namely drinking the coffee. I end up needing to write something like this:where I am passing to
put_in_coffee
both the milk to put in it, and also the action (drink_coffee
) to execute once the milk has been put in. Such code becomes hard to write, and read, and debug.In this case, we could rewrite the code in the question as:
Enter promises
This was the motivation for the notion of a "promise", which is a particular type of value which represents a future or asynchronous outcome of some sort. It can represent something that already happened, or that is going to happen in the future, or might never happen at all. Promises have a single method, named
then
, to which you pass an action to be executed when the outcome the promise represents has been realized.In the case of our milk and coffee, we design
order_milk
to return a promise for the milk arriving, then specifyput_in_coffee
as athen
action, as follows:One advantage of this is that we can string these together to create sequences of future occurrences ("chaining"):
Let's apply promises to your particular problem. We will wrap our request logic inside a function, which returns a promise:
Actually, all we've done is added a
return
to the call to$.ajax
. This works because jQuery's$.ajax
already returns a kind of promise-like thing. (In practice, without getting into details, we would prefer to wrap this call so as for return a real promise, or use some alternative to$.ajax
that does so.) Now, if we want to load the file and wait for it to finish and then do something, we can simply sayfor instance,
When using promises, we end up passing lots of functions into
then
, so it's often helpful to use the more compact ES6-style arrow functions:The
async
keywordBut there's still something vaguely dissatisfying about having to write code one way if synchronous and a quite different way if asynchronous. For synchronous, we write
but if
a
is asynchronous, with promises we have to writeAbove, we said, "JavaScript has no way to know that it needs to wait for the first call to finish before it executes the second". Wouldn't it be nice if there was some way to tell JavaScript that? It turns out that there is--the
await
keyword, used inside a special type of function called an "async" function. This feature is part of the upcoming version of ECMAScript (ES), but it is already available in transpilers such as Babel given the right presets. This allows us to simply writeIn your case, you would be able to write something like