在 JavaScript 中,我/应该如何将 async/await 与 XMLHttpRequest 一起使用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48969495/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In JavaScript how do I/should I use async/await with XMLHttpRequest?
提问by jkupczak
Full disclosure: I'd qualify myself as having intermediate JavaScript knowledge. So this is slightly above my experience level at this time.
完全披露:我认为自己具有中级 JavaScript 知识。所以这略高于我此时的经验水平。
I've got a Google Chrome Extension that does an AJAX request for a local file:///as soon as a page loads. After I get the response back from the request I use the returned code in several functions later on in my code. Most of the time I get the response back before my code that needs it runs. But sometimes I don't and everything breaks.
我有一个 Google Chrome 扩展程序,它会file:///在页面加载后立即向本地发出 AJAX 请求。从请求中得到响应后,我稍后在代码中的几个函数中使用返回的代码。大多数情况下,我会在需要它的代码运行之前得到响应。但有时我不这样做,一切都会破裂。
Now, I assume I could just throw all of the relevant code inside of the xhr.onloadbelow. But that seems really inefficient? I have a lot of moving parts that rely on the response and it seems bad to put them all in there.
现在,我假设我可以将所有相关代码扔到xhr.onload下面。但这似乎真的效率低下?我有很多依赖响应的移动部件,将它们全部放在那里似乎很糟糕。
I've perused several articles related to async/await and I'm having trouble grasping the concept. I'm also not 100% positive I'm looking at this the right way. Should I even be considering using async/await?
我已经阅读了几篇与 async/await 相关的文章,但我无法理解这个概念。我也不是 100% 肯定我正在以正确的方式看待这个问题。我是否应该考虑使用 async/await?
Here is the code for my AJAX request.
这是我的 AJAX 请求的代码。
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onload = function(e) {
code = xhr.response;
};
xhr.onerror = function () {
console.error("** An error occurred during the XMLHttpRequest");
};
xhr.send();
Let's say I've got a bunch of functions that need to fire afterwards later on in my code. Right now they just look like:
假设我有一堆函数需要稍后在我的代码中触发。现在它们看起来像:
function doTheThing(code) {
// I hope the response is ready.
}
What's the best way to approach this? FYI, the FetchAPI isn't an option.
解决这个问题的最佳方法是什么?仅供参考,FetchAPI 不是一种选择。
Here's a high level view of how my code is structured.
这是我的代码结构的高级视图。
// AJAX request begins.
// ...
// A whole bunch of synchronous code that isn't dependant on
// the results of my AJAX request. (eg. Creating and appending
// some new DOM nodes, calculating some variables) I don't want
// to wait for the AJAX response when I could be building this stuff instead.
// ...
// Some synchronous code that is dependant on both my AJAX
// request and the previous synchronous code being complete.
// ...
// Some more synchronous code that needs the above line to
// be complete.
回答by Th?ng Tr?n Xuan
I usually do async/await like this:
我通常像这样执行异步/等待:
async function doAjaxThings() {
// await code here
let result = await makeRequest("GET", url);
// code below here will only execute when await makeRequest() finished loading
console.log(result);
}
document.addEventListener("DOMContentLoaded", function () {
doAjaxThings();
// create and manipulate your DOM here. doAjaxThings() will run asynchronously and not block your DOM rendering
document.createElement("...");
document.getElementById("...").addEventListener(...);
});
此处承诺的 xhr 功能:
function makeRequest(method, url) {
return new Promise(function (resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response);
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
回答by Ronnie Royston
I create a promise for the XHR. Then simply use awaitinside an asyncfunction to call it.
我为 XHR 创建了一个承诺。然后只需await在async函数内部使用即可调用它。
function getHTML(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'document';
xhr.onload = function () {
var status = xhr.status;
if (status == 200) {
resolve(xhr.response.documentElement.innerHTML);
} else {
reject(status);
}
};
xhr.send();
});
}
async function schemaPageHandler(){
try {
var parser = new window.DOMParser();
var remoteCode = await getHTML('https://schema.org/docs/full.html');
var sourceDoc = parser.parseFromString(remoteCode, 'text/html');
var thingList = sourceDoc.getElementById("C.Thing");
document.getElementById("structured-data-types").appendChild(thingList);
} catch(error) {
console.log("Error fetching remote HTML: ", error);
}
}
回答by Jiby Jose
You get two options,
你有两个选择,
first is to use newer fetchapi which is promise based, with with you can do
首先是使用fetch基于承诺的较新的api,你可以做
let response = await fetch(url);
response = await response.json();; // or text etc..
// do what you wanna do with response
Other option if you really want to use XMLHttpRequest is to promisify it
如果你真的想使用 XMLHttpRequest 的其他选择是承诺它
let response = await new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onload = function(e) {
resolve(xhr.response);
};
xhr.onerror = function () {
resolve(undefined);
console.error("** An error occurred during the XMLHttpRequest");
};
xhr.send();
})
// do what you wanna do with response
possible full solution
可能的完整解决方案
(async () => {
let response = await new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onload = function(e) {
resolve(xhr.response);
};
xhr.onerror = function () {
resolve(undefined);
console.error("** An error occurred during the XMLHttpRequest");
};
xhr.send();
})
doTheThing(response)
})()
回答by user2704215
You can for example create an asynchronous class to use instead of the original one. It lacks some methods but it can serve as an example.
例如,您可以创建一个异步类来代替原始类来使用。它缺少一些方法,但可以作为示例。
(function() {
"use strict";
var xhr = Symbol();
class XMLHttpRequestAsync {
constructor() {
this[xhr] = new XMLHttpRequest();
}
open(method, url, username, password) {
this[xhr].open(method, url, true, username, password);
}
send(data) {
var sxhr = this[xhr];
return new Promise(function(resolve, reject) {
var errorCallback;
var loadCallback;
function cleanup() {
sxhr.removeEventListener("load", loadCallback);
sxhr.removeEventListener("error", errorCallback);
}
errorCallback = function(err) {
cleanup();
reject(err);
};
loadCallback = function() {
resolve(xhr.response);
};
sxhr.addEventListener("load", loadCallback);
sxhr.addEventListener("error", errorCallback);
sxhr.addEventListener("load", function load() {
sxhr.removeEventListener("load", load);
resolve(sxhr.response);
});
sxhr.send(data);
});
}
set responseType(value)
{
this[xhr].responseType = value;
}
setRequestHeader(header, value) {
this[xhr].setRequestHeader(header, value);
}
}
addEventListener("load", async function main() {
removeEventListener("load", main);
var xhra = new XMLHttpRequestAsync();
xhra.responseType = "json";
xhra.open("GET", "appserver/main.php/" + window.location.hash.substring(1));
console.log(await xhra.send(null));
});
}());

