Javascript 如何利用异步 XMLHttpRequest 的回调函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5485495/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I take advantage of callback functions for asynchronous XMLHttpRequest?
提问by Japboy
I'm currently writing JavaScript and confusing about callback. I've found it's not kind of built-in functions though...
I'm now reading O'Relly JavaScript 5th Edition and it shows a sample code something like below:
我目前正在编写 JavaScript 并且对callback感到困惑。我发现它不是内置函数……
我现在正在阅读 O'Relly JavaScript 5th Edition,它显示了一个示例代码,如下所示:
getText = function(url, callback) // How can I use this callback?
{
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200)
{
callback(request.responseText); // Another callback here
}
}
request.open('GET', url);
request.send();
}
Basically, I suppose I don't understand the general idea of callback
though... Could someone write a sample code to take advantage of callback
above?
基本上,我想我不明白callback
虽然......有人可以写一个示例代码来利用callback
上面的优势吗?
回答by JohnP
Callbacks are pretty simple and nifty! Because of the nature of AJAX calls, you don'tblock execution of your script till your request is over (it would be synchronous then). A callback is simply a method designated to handle the response once it gets back to your method.
回调非常简单和漂亮!由于 AJAX 调用的性质,在请求结束之前您不会阻止脚本的执行(那时它将是同步的)。回调只是一种指定的方法,用于在响应返回到您的方法后对其进行处理。
Since javascript methods are first class objects, you can pass them around like variables.
由于 javascript 方法是第一类对象,因此您可以像变量一样传递它们。
So in your example
所以在你的例子中
getText = function(url, callback) // How can I use this callback?
{
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200)
{
callback(request.responseText); // Another callback here
}
};
request.open('GET', url);
request.send();
}
function mycallback(data) {
alert(data);
}
getText('somephpfile.php', mycallback); //passing mycallback as a method
If you do the above, it means you pass mycallback
as a method that handles your response (callback).
如果您执行上述操作,则意味着您mycallback
作为处理响应(回调)的方法传递。
EDIT
编辑
While the example here doesn't illustrate the proper benefit of a callback (you could simply put the alert in the onReadyStateChange function after all!), re usability is certainly a factor.
虽然这里的例子没有说明回调的正确好处(毕竟你可以简单地将警报放在 onReadyStateChange 函数中!),但可重用性肯定是一个因素。
You have to keep in mind that the important thing here is that JS methods are first class objects. This means that you can pass them around like objects and attach them to all sorts of events. When events trigger, the methods attached to those events are called.
你必须记住,这里重要的是 JS 方法是第一类对象。这意味着您可以像对象一样传递它们并将它们附加到各种事件。当事件触发时,会调用附加到这些事件的方法。
When you do request.onreadystatechange = function(){}
you're just assigning that method to be called when the appropriate event fires.
当您这样做时,request.onreadystatechange = function(){}
您只是分配该方法在适当的事件触发时被调用。
So the cool thing here is that these methods can be reused. Say you have an error handling method that pops up an alert and populates some fields in the HTML page in the case of a 404 in the AJAX request.
所以这里很酷的事情是这些方法可以重用。假设您有一个错误处理方法,它会在 AJAX 请求中出现 404 的情况下弹出警报并填充 HTML 页面中的某些字段。
If you couldn't assign callbacks or pass methods as parameters, you'd have to write the error handling code over and over again, but instead all you have to do is just assign it as a callback and all your error handling will be sorted in one go.
如果您无法分配回调或将方法作为参数传递,则必须一遍又一遍地编写错误处理代码,而您只需将其分配为回调,所有错误处理都将被排序一气呵成。
回答by Jon
First of all I would suggest reading up on what a callback is. Hereis a start.
首先,我建议阅读什么是回调。这是一个开始。
The big picture
大图
Callbacks are used extensively in asynchronous programming. When you don't want to block until a (possibly) long-running operation completes, one of the ways to approach the problem is to delegate the operation to someone who will do it on the side for you. This raises the question: how will you be able to tell when the operation is complete, and how will you get its results?
回调在异步编程中被广泛使用。当您不想在(可能)长时间运行的操作完成之前阻塞时,解决问题的一种方法是将操作委托给会在旁边为您完成的人。这就提出了一个问题:您如何知道操作何时完成,以及如何获得结果?
One solution would be to delegate the work to someone else and take a moment off your normal work every now and then to ask "is the work I gave you done yet?". If so, get the results in some way and off you go. Problem solved.
一种解决方案是将工作委托给其他人,时不时地从你的正常工作中抽出一点时间,然后问“我交给你的工作完成了吗?”。如果是这样,请以某种方式获得结果,然后就可以了。问题解决了。
The problem with this approach is that it doesn't make your life much easier. You are now forced to ask every little while and you will not know that the operation is done as soon as it actually is (but only the next time you remember to ask). If you forget to ask, you will neverbe notified.
这种方法的问题在于它并没有让你的生活变得更轻松。您现在被迫每隔一段时间询问一次,并且您不会知道操作是否在实际完成后立即完成(但只有下次您记得询问时)。如果您忘记询问,您将永远不会收到通知。
A better solution to this is the callback: when delegating work, provide a function along with it. The code which will actually dothe work then promises to call that function as soon as the work completes. You can now forget all about that stuff and be secure in the knowledge that when the work is done, your callback will be called. No sooner, and no later.
一个更好的解决方案是回调:在委派工作时,提供一个函数。实际执行工作的代码承诺在工作完成后立即调用该函数。您现在可以忘记所有这些事情,并且知道当工作完成时,您的回调将被调用。不早,也不晚。
What is the callback here?
这里的回调是什么?
In this specific case, callback
is a function that you provide to getText
as a manner of allowing it to communicate with you. You are in effect saying "do this work for me, and when you are finished, here's a function for you to call to let me know".
在这种特定情况下,callback
是您提供的一种功能,getText
作为允许它与您进行通信的方式。你实际上是在说“为我做这项工作,当你完成后,这里有一个函数供你调用让我知道”。
getText
in fact chooses to use this callback only when the XMLHttpRequest
(XHR) is completed, and at the same time it "lets you know" it passes you the contents of the HTTP response as well (so you can act upon that information).
getText
实际上选择仅在XMLHttpRequest
(XHR) 完成时使用此回调,同时它“让您知道”它也将 HTTP 响应的内容传递给您(因此您可以根据该信息采取行动)。
Callbacks and more callbacks, oh my!
回调和更多回调,哦,天哪!
But take another moment to read the code.What is the value it stores to request.onreadystatechange
? What is the purposeof request.onreadystatechange
?
但请花一点时间阅读代码。它存储的值是request.onreadystatechange
多少?的目的是request.onreadystatechange
什么?
The answer is that request.onreadystatechange
is there for you to populate with a callback. In effect, XHR gives you a way to provide it with a callback, and it promises to "call you back" whenever the state of the underlying HTTP request changes.
答案是request.onreadystatechange
您可以使用callback进行填充。实际上,XHR 为您提供了一种为其提供回调的方法,并且它承诺在底层 HTTP 请求的状态发生变化时“回电”。
getText
is a function that builds an abstraction on top of that: It plugs its own callback (an anonymous function -- I 'll refer to that as "inner") in there and accepts anothercallback from you (the parameter -- I 'll refer to it as "outer"). When the inner callback (which, remember: gets called whenever the state changes) detects that the state is "completed" (the meaning of the value 4
) and the HTTP response status code is 200 (which means "OK"), it calls the outer callback to let you, the user of getText
, know of the result.
getText
是一个在此基础上构建抽象的函数:它在其中插入自己的回调(一个匿名函数——我将其称为“内部”)并接受来自您的另一个回调(参数——我将将其称为“外部”)。当内部回调(记住:每当状态改变时被调用)检测到状态为“完成”(值的含义4
)并且 HTTP 响应状态码为 200(表示“OK”)时,它调用外部回调让您, 的用户getText
,知道结果。
I hope I 'm making sense. :)
我希望我说得有道理。:)
回答by Mikolas Pansky
Me personally I prefer to use Event Listener over callbacks.
我个人更喜欢使用事件侦听器而不是回调。
Using Listeners comes handy especially when You're willing to process multiple asynchronous requests at once.
使用侦听器非常方便,尤其是当您愿意一次处理多个异步请求时。
The Usage is as follows (taken from https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest)
用法如下(取自https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest)
function reqListener () {
console.log(this.responseText);
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "http://www.example.org/example.txt");
oReq.send()
回答by Dingo
XMLHttpRequest callback function and files upload with data array
XMLHttpRequest 回调函数和文件上传数据数组
function HttpPost(url, arr, cb, form){
if (form === undefined) { var data = new FormData(); }else{ var data = new FormData(form); }
if (arr !== undefined) {
for (const index in arr) {
data.append(index, arr[index]);
}
}
var hr = new XMLHttpRequest();
hr.onreadystatechange=function(){
if (hr.readyState==4 && hr.status==200){
if( typeof cb === 'function' ){ cb(hr.responseText); }
}
}
hr.upload.onprogress = function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
console.log('xhr.upload progress: ' + done + ' / ' + total + ' = ' + (Math.floor(done/total*1000)/10) + '%');
};
hr.open("POST",url,true);
hr.send(data);
}
// HttpPost callback
function cb_list(res){
console.log(res);
var json = JSON.parse(res);
console.log(json.id + ' ' + json.list);
// loop
for (var objindex in json.list){
console.log(json.list[objindex].id);
}
}
Sample:
样本:
var data = [];
data["cmd"] = "get-cos";
var form = $('#form')[0];
HttpPost('/api-load', data, cb_list, form);
<form id="form" method="POST" enctype="multipart/form-data">
<input type="file" name="file[]" multiple accept="image/*">
</form>
Http header content
Http头内容
hr.setRequestHeader("Content-Type", "application/json");
// data:
var json = {"email": "[email protected]", "password": "101010"}
var data = JSON.stringify(json);
hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// data:
var data = "fname=Henry&lname=Ford";
回答by Sydwell
What works in a proper "callback" fashion is to define a service that returns a promise like this!
以适当的“回调”方式工作的是定义一个返回这样的承诺的服务!
$http.head("url2check").then(function () {
return true;
}, function () {
return false;
});
In the controller use the service:
在控制器中使用服务:
<service>.<service method>.then(function (found)) {
if (found) {......
}
@jon is correct to call it Asynchronous!
@jon 将其称为异步是正确的!