通过回调从onreadystatechange返回值

return value from onreadystatechange with callback

本文关键字:onreadystatechange 返回值 回调      更新时间:2023-09-26

我正试图从onreadystatechange AJAX调用返回一个值。。。我找到了这个页面:stackoverflow链接。我以为我让它工作,但意识到添加或删除fn函数没有什么区别。以下代码有效:

username_is_available();
function username_is_available() {
  var username = document.getElementById('username').value;
  get_data('username', username, function(returned_value) {
   if (returned_value == 'true') {
     document.getElementById('username_err').innerHTML = 'Taken';
    } else {
     document.getElementById('username_err').innerHTML = 'Available';
    };
  });
}
function get_data(data_type, data, fn) {
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function() {
  if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
    fn(xmlhttp.responseText);
  }
};
  xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
  xmlhttp.send();
}

这一切都很好,但这不是我的目标,我希望函数username_is_available()在用户名确实可用的情况下返回true。相反,在这里发生了一个操作(innerHTML被更改)。如果我尝试在匿名函数中返回,我会得到与直接从onreadystatechange:var unasigned 内部返回相同的结果

不幸的是,由于确定是否使用用户名的过程是异步的,因此无法简单地从函数调用中返回值truefalse。你可以做的是使用专门为这个目的设计的语言功能来设置类似于你现在拥有的东西(回调)。

承诺就是其中一个特点。

用法大致如下:

function username_is_available(username) {
    return new Promise(resolve => {
        get_data("username", username, resolve);
    });
}
function get_data(data_type, data, fn) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            fn(xmlhttp.responseText == "true");
        }
    };
    xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
    xmlhttp.send();
}
// Usage:
username_is_available("Ivan").then(available => {
    let text = available ? "Available" : "Taken";
    document.getElementById("username_err").innerHTML = text;
});

这依赖于availablity.phptruefalse作为文本返回,在调用resolve之前将其转换为布尔值。

将来,当ES7+asyncawait指令可用时,使用promise将非常简单(注意await关键字):

let available = await username_is_available("Ivan");
let text = available ? "Available" : "Taken";
document.getElementById("username_err").innerHTML = text;

编辑:如果你不能使用ES6或promise,那就回到好的旧回调!

function username_is_available(username, callback) {
    get_data("username", username, callback);
}
function get_data(data_type, data, fn) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            fn(xmlhttp.responseText == "true");
        }
    };
    xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
    xmlhttp.send();
}
// Usage:
username_is_available("Ivan", function(available) {
    var text = available ? "Available" : "Taken";
    document.getElementById("username_err").innerHTML = text;
});

我一直在和观察者玩,作为承诺的替代方案。我在plnkr中设置了一个例子来展示它是如何工作的。我认为在你的情况下,它会是这样的:

function Producer() {
    this.listeners = [];
}
Producer.prototype.add = function(listener) {
    this.listeners.push(listener);
};
Producer.prototype.remove = function(listener) {
    var index = this.listeners.indexOf(listener);
    this.listeners.splice(index, 1);
};
Producer.prototype.notify = function(message) {
    this.listeners.forEach(function(listener) {
        listener.update(message);
    });
};
var notifier = new Producer;
function get_data(data_type, data) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            notifier.notify(xmlhttp.responseText);
        }
    };
    xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true);
    xmlhttp.send();
}
var username_is_available = {
    update: function(returned_value) {
        var username = document.getElementById('username').value;
        if (returned_value == 'true') {
            document.getElementById('username_err').innerHTML = 'Taken';
        } else {
            document.getElementById('username_err').innerHTML = 'Available';
        };        
    }
}
notifier.add(username_is_available);
get_data("username", username);

注意,Producer代码是可重用的,您可以为其他ajax/可观察请求创建一个新实例。

相关文章:
  • 没有找到相关文章