异步/等待,XHR请求后返回的变量未定义

时间:2019-01-25 00:24:19

标签: javascript async-await

我正在尝试从API获取公共IP地址,然后将该IP用于其他功能(ninjaUniqueVisitorRequest())。

我有以下代码:

function ninjaGetIp() {
    var ipRequest = new XMLHttpRequest();
    ipRequest.open('GET', "https://api.ipify.org?format=jsonp=", true);
    ipRequest.send();
    ipRequest.onload = function () {
        if (ipRequest.status >= 200 && ipRequest.status < 400) { // If response is all good...
            return ipRequest.responseText;
        } else {
            console.log('There was an error retrieving the public IP.');
            return '127.0.0.1'; 
        }
    }
}

async function ninjaUniqueVisitorRequest() {
    // var ninjaSiteUuid = ninjaGetSiteUuid();
    // var ninjaFingerprint = await ninjaGetFingerprint();
    var ninjaPublicIp = await ninjaGetIp();
    console.log(ninjaPublicIp);
}

当前,当我运行ninjaUniqueVisitorRequest();时,console.log(ninjaPublicIp);返回undefined

我有点理解它会在发出请求之前立即返回,但这就是我认为我正在使用async/await修复的问题。

任何想法都值得赞赏! PHP家伙在这里,对我好一点。

2 个答案:

答案 0 :(得分:1)

这是因为ninjaGetIp不可等待。您必须返回Promise才能await

   async function ninjaGetIp() {
        return new Promise( (resolve, reject) => {
            var ipRequest = new XMLHttpRequest();
            ipRequest.open('GET', "https://api.ipify.org?format=jsonp=", true);
            ipRequest.send();
            ipRequest.onload = () => {
                if (ipRequest.status >= 200 && ipRequest.status < 400) { // If response is all good...
                    resolve(ipRequest.responseText);
                } else {
                    console.log('There was an error retrieving the public IP.');
                    reject('127.0.0.1');
                }
            }
        });

    }

此外,您可以简化它并使用fetch来返回一个承诺,而不用使用构建XMLHttpRequest所需的所有代码:

async function ninjaGetIp() {
    return fetch('https://api.ipify.org?format=jsonp=');
}

TL; DR;

如果您想坚持使用XMLHttpRequest,我将为其创建包装器,因为它有很多冗余代码:这是一个示例:

class HttpClient {
    constructor(){}
    async get(url) {
        return new Promise( (resolve, reject) => {
            const xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = (evt) => {
                if (evt.currentTarget.readyState === 4 && evt.currentTarget.status === 200) {
                    try {
                        const response = JSON.parse(evt.currentTarget.response);
                        resolve(response);
                    } catch (exception) {
                        reject(exception);
                    }
                }
            };
            xhttp.open('GET', url, true);
            xhttp.send();
        });
    }
    async post(url, data) {
        return new Promise( (resolve, reject) => {
            const xhttp = new XMLHttpRequest();
            xhttp.onreadystatechange = (evt) => {
                if (evt.currentTarget.readyState === 4 && evt.currentTarget.status === 200) {
                    try {
                        const response = JSON.parse(evt.currentTarget.response);
                        resolve(response);
                    } catch (exception) {
                        reject(exception);
                    }
                }
            };
            xhttp.open('POST', url, true);
            xhttp.send(data);
        });
    }
}

用法

const httpClient = new HttpClient();
const data = await httpClient.get('some url');
  1. Fetch API
  2. Async
  3. Await

答案 1 :(得分:1)

当前您的ninjaGetIp并不值得期待。Promise

您可以尝试返回一个包含实现的新Promise

function ninjaGetIp() {
    return new Promise(function (resolve, reject) {
        var ipRequest = new XMLHttpRequest();
        ipRequest.open('GET', "https://api.ipify.org?format=jsonp=", true);
        ipRequest.send();
        ipRequest.onload = function () {
            if (ipRequest.status >= 200 && ipRequest.status < 400) { // If response is all good...
                return resolve(ipRequest.responseText);
            } else {
                console.log('There was an error retrieving the public IP.');
                return resolve('127.0.0.1'); 
            }
        }
    });

}