javascript - 浏览器中的异步 XMLHttpRequest 阻塞 UI
问题描述
我在 Web 应用程序的客户端具有以下功能:
function fetchDataFromApi(fetchCode, options, callback) {
var dataObject = JSON;
dataObject.fetchCode = fetchCode;
dataObject.options = options;
var xhr = new XMLHttpRequest();
var url = "DATA_API_URL";
// connect to the API
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type",
"application/json"
);
// set callback for when API responds. This will be called once the request is answered by the API.
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// API has responded;
var json = {
ok: false,
message: 'could not parse response'
};
try {
// parse the raw response into the API response object
json = JSON.parse(xhr.responseText);
} catch (err) {
// probably json parse error; show raw response and error message
console.log(err);
console.log("raw response: " + xhr.responseText);
}
if (json.ok) {
// success, execute callback with argument json.data
callback(json.data);
} else {
// fetch failed;
console.error(json.message);
}
}
};
// send request payload to API
var data = JSON.stringify(dataObject);
xhr.send(data);
}
由于我使用的是异步调用(中的第三个参数xhr.open
设置为true
),我惊讶地发现这个函数会阻塞浏览器中的 UI。当使用此功能从服务器抓取大量数据时,可能需要 3-4 秒,阻塞 UI 并在 Chrome 控制台中生成此错误:
[Violation] 'load' handler took 3340ms
这个函数目前在这里生产,我在这里调用这个函数:
function getNamesFromApi() {
fetchDataFromApi('chj-confraternity-list', {}, function (data) {
fadeReplace(document.getElementById('spinner-2'), document.getElementById(
'name-list-container'),
false, true);
// transaction was successful; display names
var listString = "";
if (data.list) {
// add the names to the page
var listLength = data.list.length;
for (var x = 0; x < listLength; x++) {
document.getElementById('name-list-container').innerHTML +=
"<div class='name-list-item'>" +
"<span class='name-list-name'>" +
data.list[x].name +
"</span>" +
"<span class='name-list-location'>" +
data.list[x].location +
"</span>" +
"</div>";
}
}
});
}
window.addEventListener('load', function() {
getNamesFromApi();
});
为什么这会阻塞 UI,我在制作异步 XMLHttpRequest 时做错了什么?
更新:感谢评论为我指明了正确的方向;问题不是 XMLHttpRequest,而是我在循环中附加了 innerHTMl。该问题现已解决,答案中包含更正的代码段。
解决方案
UI 被阻止是因为我在循环中附加了 innerHTML,这是一个昂贵的 UI 阻塞操作。该问题现已修复。这是更正后的片段:
function getNamesFromApi() {
fetchDataFromApi('chj-confraternity-list', {}, function (data) {
fadeReplace(document.getElementById('spinner-2'), document.getElementById(
'name-list-container'),
false, true);
// transaction was successful; display names
if (data.list) {
var listString = "";
// add the names to the page
var listLength = data.list.length;
for (var x = 0; x < listLength; x++) {
listString +=
"<div class='name-list-item'>" +
"<span class='name-list-name'>" +
data.list[x].name +
"</span>" +
"<span class='name-list-location'>" +
data.list[x].location +
"</span>" +
"</div>";
}
document.getElementById('name-list-container').innerHTML = listString;
}
});
}
window.addEventListener('load', function() {
getNamesFromApi();
});
推荐阅读
- python-3.x - 如何通过 task_id 访问 Celery 链结果?
- java - 上传文件(Mac OS 到 USS)可能会损坏 I
- java - 如何使用 Gson 将 JSON 映射转换为自定义 Java 列表?
- php - 将一系列模型关系链接到查询构建器
- javascript - 将数据从服务器发送到客户端(节点 JS + webpack
- java - 服务器主机:端口似乎不是 Spring Boot 中嵌入 MongoDB 中已启动副本集的成员
- python - 线检测问题 - Python 中的 OpenCV
- bash - 如何区分 youtube-dl 获取 ctrl-c 和 shell 脚本中的其他错误?
- python - Python 中的“线程”库 并发还是并行?
- python - 在 Signal Handler、Asyncio 中调用 Async 函数