函数在分配正确的值之前不等待分配响应

function doesnt wait for response to be assigned before assigning the correct value

我在 ext js.file 上有一个 xhr 函数,它向 rest 服务发送值并期望返回响应。 我在单击事件 btn 上调用此函数。第一次它响应 "undefined" 然后当我再次按下按钮时它以正确的值响应。我几乎可以肯定我的响应不是即时的,但为什么函数不能等到它有值然后将它分配给我的 return 值,而不是发送给我未定义的值。

var b;

function Transport(parameters, Page) {

    var http = new XMLHttpRequest();

    http.open("POST", "http://***.***.***.***/" + Page, true);

    //Send the proper header information along with the request
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    http.setRequestHeader("Content-length", parameters.length);

    http.onreadystatechange = function() { //Call a function when the state   changes.
        if (http.readyState == 4 && http.status == 200) {

            b = http.response;
        }
    }
    http.send(parameters);
    return b;
}

页面上函数的调用

var transaction = Transport(parameters,"/mypage.php");
alert(transaction);

当您调用 Transport() 发送请求时,b 已经存在并具有值 undefined。该调用是异步的,因此 returns 立即调用,无需等待请求完成。该请求仍在后台处理,并在您第二次点击按钮时完成。当它完成时它设置 b,它由第二次调用返回。

如果您将代码更改为如下所示,行为会更像您所期望的:

function doSomethingWithMyData(data) {
    ...
}

function Transport(parameters, page) {
    var http = new XMLHttpRequest();

    http.open("POST", "http://***.***.***.***/" + page, true);

    //Send the proper header information along with the request
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    http.setRequestHeader("Content-length", parameters.length);

    http.onreadystatechange = function() { //Call a function when the state   changes.
        function() {
            if(http.readyState == 4 && http.status == 200) {
                doSomethingWithMyData(http.reponse);
            }
        }
    }
    http.send(parameters);
}

...

var transaction = Transport(parameters,"/mypage.php");

您正在尝试在异步模式下使用 httprequest。其中 http.send() returns 立即。您可以尝试使用 Asynch to False 来编写您的代码。

var b;
function Transport(parameters,Page) { 
 var http = new XMLHttpRequest();
 http.open("POST", "http://***.***.***.***/"+Page, false);

  //Send the proper header information along with the request
  http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  http.setRequestHeader("Content-length", parameters.length);
  http.send(parameters);
  b=http.response;
  return b;
 }

更多信息请参考http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp

您正在发出 异步 请求,但试图 同步 处理结果。相反,使用回调。

function transport(parameters, Page, callback) { // not a constructor, cammel case
    var xhr = new XMLHttpRequest();

    xhr.open("POST", "http://***.***.***.***/" + Page);

    //Send the proper header information along with the request
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    // don't set content-length, you'll get a warning

    xhr.addEventListener('load', function () {
        callback(this.response, this);
    });
    xhr.send(parameters);
    return xhr;
}

然后

transport(
    parameters,
    "/mypage.php",
    function (response) {alert(response);}
);

在 ES6 中我们可以写成 Promise

/**
 * Fetches a resource using XMLHttpRequest and a Promise
 * @param {String} url - The URL of the resource to get
 * @param {String|FormData|Blob|File} [postData] - Any data to POST
 * @param {String} [responseType] - The type of response to expect (defaults to document)
 * @returns {Promise}
 */
function fetch(url, postData, responseType) {
    return new Promise((res, rej) => {
        var x = new XMLHttpRequest();
        x.responseType = responseType || 'document';
        x.addEventListener('load', e => res(x.response, x));
        x.addEventListener('error', e => {
            console.warn('XHR Error', url, e);
            rej(x.response, x);
        });
        if (!postData) {
            x.open('GET', url);
            x.send();
        } else {
            x.open('POST', url);
            if ('string' === typeof postData)
                x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            x.send(postData);
        }
    });
}

然后

fetch(Page, parameters, 'text').then(alert);