异步/等待,XHR 请求后返回的变量未定义
Posted
技术标签:
【中文标题】异步/等待,XHR 请求后返回的变量未定义【英文标题】:Async/Await, returned variable is undefined after XHR request 【发布时间】:2019-06-18 19:43:20 【问题描述】:我正在尝试从 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的家伙在这里,放轻松。
【问题讨论】:
你的ninjaGetIp()
函数不是 async
并且不返回 Promise。
我以为你只是把async
放在你调用的函数上。同样据我了解return xyz
无论如何都会转换为承诺?我正在用 Babel 编译。
如果你想要基于承诺的 AJAX 使用 fetch() API。
@KriiV 如果你有 any return
并且你用async
标记它,它将被转换为一个承诺。 ninjaGetIp
不返回任何内容。
How do I return the response from an asynchronous call?的可能重复
【参考方案1】:
目前您的ninjaGetIp
不是可等待的Promise
。
您可以尝试只返回一个新的 Promise
来包装实现,或者只是在函数前添加 async
关键字。
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');
);
异步示例
async 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';
【讨论】:
【参考方案2】:那是因为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');
-
Fetch API
Async
Await
【讨论】:
我将 XHR 用于兼容性目的...但不确定这是否正确。XHR
仍然具有fetch
中不存在的功能 - 所以,使用 XHR 是完美的 - 但是,问题中的代码不使用任何这些功能
如果响应中有错误代码,您的 HttpClient
会留下未解决的承诺。您还重复了大量可以在 get()
和 post()
方法之间轻松共享的代码。
同意。在这方面有很多工作要做,以使其为生产做好准备。这是一个快速示例,说明如何抛出他现有的代码并将其包装在一个类中。更不用说它缺少其余的 HTTP 动词(PATCH、DELETE、PUT 等......)以上是关于异步/等待,XHR 请求后返回的变量未定义的主要内容,如果未能解决你的问题,请参考以下文章
使用 Chrome + XHR 时未定义 PHP POST 变量