JS отказался от синхронных вызовов в главном потоке, насколько это рискованно? - PullRequest
0 голосов
/ 04 ноября 2018

У меня есть одностраничное веб-приложение. Часть его поведения основывается на изменении раздела страницы и последующем вызове некоторых функций для форматирования этого раздела ПОСЛЕ того, как он был изменен (MathJax является одним из наиболее важных вызовов после модификации, которые мне нужно сделать).

Поскольку Ajax является асинхронным, иногда я не получал желаемого эффекта, поскольку получал неформатированную страницу, поскольку сценарии запускались до того, как содержимое страницы было готово, чтобы исправить это, я начал вызовите XMLHttpRequest().open() с false, чтобы сделать его синхронным и убедиться, что содержимое страницы было готово перед вызовом сценариев.

Это, однако, заставляет страницу выдавать предупреждение

"Синхронный XMLHttpRequest в основном потоке устарел из-за его вредные последствия для конечного пользователя. "

несмотря на то, что поведение именно то, что мне нужно. Мне не нравится полагаться на устаревшее поведение, потому что оно может работать сейчас, но через 2 месяца, если они что-то изменят и сломают, мне придется переформатировать весь код и снова решить проблему другим способом.

Насколько я должен быть обеспокоен этим предупреждением, и если оно может быть повреждено в будущих обновлениях Интернета, что я должен делать вместо этого?

EDIT: 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 голосов
/ 04 ноября 2018

Насколько я должен быть обеспокоен этим предупреждением,

Разумно. :-) Это говорит вам, что это плохая практика по причине: это отрицательно влияет на пользовательский опыт.

... что мне делать вместо этого?

Просто продолжайте использовать асинхронный 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 :

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
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...