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

时间:2011-03-30 11:08:02

标签: javascript asynchronous callback xmlhttprequest

我目前正在编写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的一般概念......有人可以写一个示例代码来利用上面的callback吗?

5 个答案:

答案 0 :(得分:46)

回调非常简单和漂亮!由于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页面中的某些字段。

如果你不能指定回调或传递方法作为参数,你必须一遍又一遍地编写错误处理代码,但你要做的就是将它作为回调和所有错误处理分配将一次排序。


答案 1 :(得分:17)

首先,我建议阅读回调内容。 Here是一个开始。

大图

回调在异步编程中广泛使用。如果您不希望在(可能)长时间运行的操作完成之前阻塞,则解决问题的方法之一是将操作委派给将为您执行此操作的人员。这提出了一个问题:你如何能够判断操作何时完成,以及如何获得结果?

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

这种方法的问题在于它不会让您的生活更轻松。你现在被迫每隔一段时间就会问一次,你不会知道操作是否已经完成(但只有下次你记得要问)。如果您忘记提问,您将从不收到通知。

更好的解决方案是回调:委派工作时,提供一个功能。实际上工作的代码然后承诺在工作完成后立即调用该函数。你现在可以忘记所有这些东西,并且知道当工作完成后,你的回调将被调用。不久,不迟。

这里的回调是什么?

在这种特定情况下,callback是您向getText提供的一种功能,允许它与您通信。你实际上在说“为我做这项工作,当你完成后,这是一个让你打电话告诉我的功能”。

getText实际上只在XMLHttpRequest(XHR)完成时选择使用此回调,同时它“让你知道”它会将HTTP响应的内容传递给你好吧(所以你可以根据这些信息采取行动)。

回调和更多回调,哦,我的!

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

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

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

我希望我有道理。 :)

答案 2 :(得分:1)

我个人更喜欢使用Event Listener而不是回调。

使用Listeners非常方便,特别是当您愿意一次处理多个异步请求时。

用法如下(取自https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

id_status

答案 3 :(得分:0)

什么在合适的"回调"时尚是定义一个返回这样的承诺的服务!

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

在控制器中使用服务:

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

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

答案 4 :(得分:0)

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": "hey@mail.xx", "password": "101010"}
var data = JSON.stringify(json);

hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// data: 
var data = "fname=Henry&lname=Ford";