JS不赞成在主线程上进行同步调用,这有多大风险?

时间:2018-11-04 18:18:52

标签: javascript ajax multithreading

我有一个单页Web应用程序。它的某些行为依赖于修改页面的一部分,然后在修改页面后调用一些函数来格式化该部分(MathJax是我需要做的最重要的修改后调用之一)。

由于Ajax是异步的,所以有时候我没有得到想要的效果,因为我会得到未格式化的页面,因为脚本会在页面内容准备就绪之前运行,为了解决这个问题,我开始用XMLHttpRequest().open()调用false以使其同步,并在调用脚本之前确保页面内容已准备就绪。

但这会使页面发出警告

“不赞成在主线程上使用同步XMLHttpRequest,因为它 对最终用户的体验产生不利影响。”

尽管行为正是我所需要的。我不喜欢依靠不赞成使用的行为,因为它现在可能会起作用,但是如果他们改变并破坏了它,则需要两个月的时间,我不得不重新格式化整个代码,并以另一种方式再次解决问题。

我应该如何处理此警告,如果以后的网络更新可能会破坏该警告,我该怎么办?

编辑: JS代码:

function changeSection(section, page, button, sync=true)
{
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      $(section).empty();
      $(section).append(this.responseText);

      clearButtons();
      setButton(button);
    }
  };
  xhttp.open("GET", page, sync);
  xhttp.send();
}

function setLagrange() {
  path = MathLog_path + "modelling/lagrange_interpolation.html";

  changeSection("#VolatileSection", path, "lagrange_button", false);

  $('pre code').each(function(i, block) {
    hljs.highlightBlock(block);
  });
  MathJax.Hub.Config({
    tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
  });
  MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
}

1 个答案:

答案 0 :(得分:2)

  

我应该如何担心这个警告,

合理地。 :-)告诉您这是不好的做法,其原因是:它会对用户体验产生负面影响。

  

...我应该怎么做?

只需继续使用异步ajax,并在完成处理程序中调用需要调用的函数即可。

如果使用XHR:

const xhr = new XMLHttpRequest();
xhr.addEventListener("load", () => {
    // Call your functions here
});
xhr.addEventListener("error", () => {
    // Handle errors here
});
xhr.open("GET", "/path/to/the/resource");
xhr.send();

...但是我会使用fetch

fetch("/path/to/the/resource")
.then(response => {
    if (!response.ok) {
        throw new Error("HTTP error " + response.status);
    }
    return response.appropriateMethodToReadBodyHere();
})
.then(data => {
    // Call your functions here
})
.catch(error => {
    // Handle errors here
});

...甚至在async function中也可能:

try {
    const response = await fetch("/path/to/the/resource");
    if (!response.ok) {
        throw new Error("HTTP error " + response.status);
    }
    const data = await response.appropriateMethodToReadBodyHere();
    // Call your functions here
} catch (error) {
    // Handle errors here
}

您添加了一些代码。这是一个最小的变化示例:

function changeSection(section, page, button, sync=true, callback = () => {})
// *** ------------------------------------------------^^^^^^^^^^^^^^^^^^^^^
{
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      $(section).empty();
      $(section).append(this.responseText);

      clearButtons();
      setButton(button);
      callback(); // ***
    }
  };
  xhttp.open("GET", page, sync);
  xhttp.send();
}

function setLagrange() {
  path = MathLog_path + "modelling/lagrange_interpolation.html";

  changeSection("#VolatileSection", path, "lagrange_button", false, () => {
  // *** ---------------------------------------------------------^^^^^^^^^
      $('pre code').each(function(i, block) {
        hljs.highlightBlock(block);
      });
      MathJax.Hub.Config({
        tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
      });
      MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
  });
//^^^ ***
}

...但是当您使用ES2015 +功能时,我将使用fetch并从changeSection返回承诺:

function changeSection(section, page, button, sync=true)
{
  return fetch(page)
    .then(response => {
      if (!response.ok) {
          throw new Error("HTTP error " + response.status);
      }
      return response.text(); // or .json() or whatever
    })
    .then(() => {
      $(section).empty();
      $(section).append(this.responseText);

      clearButtons();
      setButton(button);
    });
}

function setLagrange() {
  path = MathLog_path + "modelling/lagrange_interpolation.html";

  changeSection("#VolatileSection", path, "lagrange_button", false).then(() => {
  // *** ----------------------------------------------------------^^^^^^
      $('pre code').each(function(i, block) {
        hljs.highlightBlock(block);
      });
      MathJax.Hub.Config({
        tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
      });
      MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
  });
}

或使用async函数:

async function changeSection(section, page, button, sync=true)
{
  const response = await fetch(page);
  if (!response.ok) {
      throw new Error("HTTP error " + response.status);
  }
  await response.text(); // or .json() or whatever
  $(section).empty();
  $(section).append(this.responseText);

  clearButtons();
  setButton(button);
}

async function setLagrange() {
  path = MathLog_path + "modelling/lagrange_interpolation.html";

  await changeSection("#VolatileSection", path, "lagrange_button", false);
  $('pre code').each(function(i, block) {
    hljs.highlightBlock(block);
  });
  MathJax.Hub.Config({
    tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
  });
  MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
}

请注意,setLagrange必须从async函数中调用,否则必须明确使用其承诺:

setLagrange(/*...*/)
.catch(error => {
    // Handle error
});