如何利用异步 XMLHttpRequest 的回调函数?

发布于 2024-10-28 04:50:58 字数 588 浏览 2 评论 0原文

我目前正在编写 JavaScript,并对回调感到困惑。我发现它不是一种内置函数...
我现在正在阅读 O'Relly JavaScript 第 5 版,它显示了一个示例代码,如下所示:

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();
}

基本上,我想我不明白 callback 的一般思想...有人可以写一个利用上面的回调的示例代码?

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:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一江春梦 2024-11-04 04:50:58

回调非常简单又漂亮!由于 AJAX 调用的性质,您不会阻止脚本的执行,直到请求结束(那时它将是同步的)。回调只是一种指定在响应返回到您的方法后处理响应的方法。

由于 javascript 方法是第一类对象,因此您可以像变量一样传递它们。

因此,在您的示例中

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

,如果执行上述操作,则意味着您将 mycallback 作为处理响应(回调)的方法传递。

编辑

虽然这里的示例没有说明回调的适当好处(毕竟您可以简单地将警报放在 onReadyStateChange 函数中!),但可重用性无疑是一个因素。

你必须记住,这里重要的是 JS 方法是第一类对象。这意味着您可以像对象一样传递它们并将它们附加到各种事件。当事件触发时,将调用附加到这些事件的方法。

当您执行 request.onreadystatechange = function(){} 时,您只是指定在适当的事件触发时调用该方法。

所以这里最酷的事情是这些方法可以重用。假设您有一个错误处理方法,当 AJAX 请求中出现 404 错误时,该方法会弹出警报并填充 HTML 页面中的某些字段。

如果您无法分配回调或将方法作为参数传递,则必须一遍又一遍地编写错误处理代码,但您所要做的只是将其分配为回调,所有错误处理都会被排序一口气。


Callbacks are pretty simple and nifty! Because of the nature of AJAX calls, you don't block 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.

Since javascript methods are first class objects, you can pass them around like variables.

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).

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.

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.

When you do request.onreadystatechange = function(){} you're just assigning that method to be called when the appropriate event fires.

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.

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.


萌酱 2024-11-04 04:50:58

首先,我建议阅读什么是回调。 这里是一个开始。

总体情况

回调在异步编程中广泛使用。当您不想在(可能)长时间运行的操作完成之前阻塞时,解决该问题的方法之一是将操作委托给可以为您完成的人。这就提出了一个问题:您如何知道操作何时完成,以及如何获得结果?

一种解决方案是将工作委托给其他人,并时不时地从正常工作中抽出一点时间来问“我交给你的工作完成了吗?”。如果是这样,请以某种方式获得结果,然后就可以出发了。问题解决了。

这种方法的问题在于它并没有让你的生活变得更轻松。现在,您被迫每隔一段时间就询问一次,并且您不会知道操作实际上已完成(但只有在您下次记得询问时才知道)。如果您忘记询问,您将永远不会收到通知。

一个更好的解决方案是回调:在委派工作时,同时提供一个函数。实际执行工作的代码承诺在工作完成后立即调用该函数。现在,您可以忘记所有这些事情,并且可以放心地知道,当工作完成时,您的回调将被调用。不早不晚。

这里的回调是什么?

在这种特定情况下,callback 是您提供给 getText 的函数,作为允许它与您通信的方式。您实际上是在说“为我完成这项工作,当您完成后,您可以调用以下函数来通知我”。

事实上,getText 仅在 XMLHttpRequest (XHR) 完成时才选择使用此回调,同时它“让您知道”它向您传递了还有 HTTP 响应(以便您可以根据该信息采取行动)。

回调和更多回调,天哪!

但是请再花点时间阅读代码。它存储到 request.onreadystatechange 的值是什么? request.onreadystatechange目的是什么?

答案是 request.onreadystatechange 可供您填充回调。实际上,XHR 为您提供了一种为其提供回调的方法,并且它承诺每当底层 HTTP 请求的状态发生变化时就会“回调您”。

getText 是一个在其之上构建抽象的函数:它插入自己的回调(一个匿名函数 - 我将其称为“内部函数”) ") 并接受来自您的另一个回调(参数 - 我将其称为“outer”)。当内部回调(记住:每当状态发生变化时就会被调用)检测到状态已“完成”(值 4 的含义)并且 HTTP 响应状态代码为 200(这意味着“OK”),它调用外部回调让您(getText 的用户)知道结果。

我希望我说得有道理。 :)

First of all I would suggest reading up on what a callback is. Here is 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 never be notified.

A better solution to this is the callback: when delegating work, provide a function along with it. The code which will actually do the 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".

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).

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 purpose of 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.

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 another callback 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.

I hope I 'm making sense. :)

后eg是否自 2024-11-04 04:50:58

我个人更喜欢使用事件监听器而不是回调。

使用侦听器会很方便,尤其是当您愿意一次处理多个异步请求时。

用法如下(取自 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()

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)

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()
花海 2024-11-04 04:50:58

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);
    }
}

示例:

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 标头内容

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";

XMLHttpRequest callback function and files upload with data array

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

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";
ゞ记忆︶ㄣ 2024-11-04 04:50:58

以正确的“回调”方式起作用的是定义一个返回这样的承诺的服务!

$http.head("url2check").then(function () {
                return true;
            }, function () {
                return false;
            });

在控制器中使用服务:

<service>.<service method>.then(function (found)) {
     if (found) {......
}

@jon 将其称为异步是正确的!

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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文