首页 > 解决方案 > XML 文件无法解析 - 同步 XMLHttpRequest 已贬值

问题描述

我的 HTML、JavaScript 和 XML 会计系统不再完全可以在 Firefox 中运行,但可以在 Google Chrome 中运行。在 Firefox 中检查页面,我在控制台选项卡下看到以下错误消息:

主线程上的同步 XMLHttpRequest 已被弃用,因为它会对最终用户的体验产生不利影响。如需更多帮助http://xhr.spec.whatwg.org/

在我看来,同步使用 XMLHttpRequest 已被弃用,因为它有时会在等待响应时冻结页面。我在 JavaScript 程序中使用 XMLHttpRequest 的唯一一次是在解析 XML 文件时。我解析 XML 文件的方式与此处的 W3School XML 教程中目前概述的方式完全相同:

https://www.w3schools.com/xml/tryit.asp?filename=tryxml_parsertest

本教程使用同步 XMLHttpRequest,由 xmlhttp.open("GET", "note.xml", false); 行中的 'false' 设置。我的笔记说异步加载已关闭,以防止脚本在文档完全加载之前运行。我试图将“假”更改为“真”,但这也不起作用。

我不完全确定这是否是我的问题,因为 W3C 教程示例仍然适用于 Firefox。但是,Firefox 控制台确实显示了相同的“已弃用 XMLHttpRequest 的同步使用”警告。它还显示了许多其他警告。

我对问题的理解正确吗?

如果是这样,您能否说明现在应该如何编写 W3School XML 解析代码?为方便起见,我在下面粘贴了原始教程代码的副本:

<!DOCTYPE html>
<html>
<body>
<h1>W3Schools Internal Note</h1>
<div>
<b>To:</b> <span id="to"></span><br>
<b>From:</b> <span id="from"></span><br>
<b>Message:</b> <span id="message"></span>
</div>

<script>
var xmlhttp, xmlDoc;
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "note.xml", false);
xmlhttp.send();
xmlDoc = xmlhttp.responseXML;
document.getElementById("to").innerHTML=
xmlDoc.getElementsByTagName("to")[0].childNodes[0].nodeValue;
document.getElementById("from").innerHTML=
xmlDoc.getElementsByTagName("from")[0].childNodes[0].nodeValue;
document.getElementById("message").innerHTML=
xmlDoc.getElementsByTagName("body")[0].childNodes[0].nodeValue;
</script>

脚本的前 5 行处理解析 XML 文件,脚本的其余部分将 XML 文件中的信息插入到网页中。

感谢您的帮助!!!

标签: xml

解决方案


关于同步的警告XMLHttpRequest就是一个警告。在本地测试,该请求仍然在 Firefox、Chrome 和 Safari 下执行并正确解析。但是,不清楚您所说的“不再完全有效”是什么意思,所以也许您可以详细说明在这种情况下究竟什么是/不工作。

在我看来,同步使用 XMLHttpRequest 已被弃用,因为它有时会在等待响应时冻结页面。

实际上,您可能会遇到警告消息中提到的“有害影响”的示例。

我的笔记说异步加载已关闭,以防止脚本在文档完全加载之前运行。

更合适的方法是为load触发的事件添加一个侦听器Window,但是,最好也异步执行请求。以下是您发布的代码的修改版本,其中:

  • 执行等待load事件
  • 异步执行请求
  • 测试响应以确保其有效
// 1) Wait for the Window `load` event to be fired
window.addEventListener('load', () => {
  const xmlhttp = new XMLHttpRequest();
  xmlhttp.open('GET', 'note.xml');
  // 2) Wait for the XMLHttpRequest `load` event to be fired
  xmlhttp.addEventListener('load', ({ target }) => {
    // 3) Ensure that the response is valid
    if (target.status < 200 || 300 <= target.status) {
      console.error(`Received status "${target.status}"`);
      return;
    }

    const contentType = target.getResponseHeader('Content-Type');
    if (contentType !== 'application/xml') {
      console.error(`Received Content-Type "${contentType}"`);
      return;
    }

    const xmlDoc = target.responseXML;
    if (xmlDoc === null) {
      console.error('Unable to parse XML response');
      return;
    }

    document.getElementById('to').innerHTML = xmlDoc.getElementsByTagName('to')[0].childNodes[0].nodeValue;
    document.getElementById('from').innerHTML = xmlDoc.getElementsByTagName('from')[0].childNodes[0].nodeValue;
    document.getElementById('message').innerHTML = xmlDoc.getElementsByTagName('body')[0].childNodes[0].nodeValue;
  });
  xmlhttp.addEventListener('error', error => {
    console.error(`Received error "${error}"`);
  });
  xmlhttp.send();
});

至于XML解析,我的理解是解析到Document使用responseXML属性与请求是同步执行还是异步执行是正交的。如果要显式处理解析,可以将使用替换为responseXML以下使用DOMParserand parseFromString

const parser = new DOMParser();
const xmlDoc = parser.parseFromString(target.responseText, contentType);
if (xmlDoc.querySelector('parsererror') !== null) {
  console.error('Unable to parse XML response');
  return;
}

最后,如果您已经走到了这一步,请考虑转而使用Fetch API,这是一种更现代、更符合人体工程学的方式,可以在浏览器中执行这些异步请求,使用Promises 并因此可以使用async/await来清理流程. 使用它,代码可以变成:

window.addEventListener('load', async () => {
  const request = new Request('note.xml');
  try {
    const response = await fetch(request);
    if (response.ok === false) {
      console.error('Response was not ok');
      return;
    }

    const contentType = response.headers.get('Content-Type');
    if (contentType !== 'application/xml') {
      console.error(`Received Content-Type "${contentType}"`);
      return;
    }

    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(await response.text(), contentType);
    if (xmlDoc.querySelector('parsererror') !== null) {
      console.error('Unable to parse XML response');
      return;
    }

    document.getElementById('to').innerHTML = xmlDoc.getElementsByTagName('to')[0].childNodes[0].nodeValue;
    document.getElementById('from').innerHTML = xmlDoc.getElementsByTagName('from')[0].childNodes[0].nodeValue;
    document.getElementById('message').innerHTML = xmlDoc.getElementsByTagName('body')[0].childNodes[0].nodeValue;
  } catch (error) {
    console.error(`Received error "${error}"`);
  }
});

推荐阅读