Почему я могу писать в sessionStorage из iframe с первой попытки, а не с любых последующих? (Chrome Version 74) - PullRequest
2 голосов
/ 29 апреля 2019

Эта проблема обнаружена в последней версии Chrome (74.0.3729.108). Это уникально для локальной файловой системы, так как у меня есть другие способы загрузки соседних документов в iframes, когда приложение находится на сервере.

В моем приложении мы смогли загрузить документы из файловой системы с помощью JavaScript, записав iframes в DOM, а затем поместив документ в iframe, записав его от innerHTML до sessionStorage. Когда загрузка iframe завершена, мы фиксируем это с помощью атрибута onload в iframe и обрабатываем получение элемента, записанного в sessionStorage.

Я сузил это до некоторого простого кода и обнаружил, что это работает только с первой попытки, а затем с любой попытки после первого сбоя.

Вот минимальный HTML-документ:

<!DOCTYPE html>
<html>
<head>
  <title>Chrome iFrame Tester</title>
  <script src="iframe-load.js"></script>
</head>
<body onload="OnLoad()">
  <div id="result"></div>
</body>
</html>

Вот код JavaScript:

var urls = ['file://C:/Users/afrench/Documents/Other/Misc%20Code/Chrome%20iFrame/Doc1.html', 
            'file://C:/Users/afrench/Documents/Other/Misc%20Code/Chrome%20iFrame/Doc2.html'];

HandleLoad = function () {
  'use strict';

  var data;

  try {
    data = window.sessionStorage['data'];
    delete window.sessionStorage['data'];
  } catch (ignore) {
    // something went wrong
  }

  var container = document.getElementById('container');
  window.document.body.removeChild(container);

  if (data !== null && data !== undefined) {
    var resultContainer = document.getElementById('result');
    resultContainer.innerHTML += data;
  }

  if (urls.length > 0) {
    OnLoad();
  }
}

function OnLoad() {
  var url = urls[0];

  if (url) {
    urls.splice(0, 1);

    var container = document.createElement('div');
    container.id = 'container';
    container.style.visibility = 'hidden';
    window.document.body.appendChild(container);
    container.innerHTML = '<iframe src="' + url + '" onload="HandleLoad();"></iframe>';
  }
}

В файловой системе HTML-код записан в index.html, а рядом с ним два минимальных HTML-файла, Doc1.html и Doc2.html. Их содержание одинаково, за исключением идентифицирующего предложения в div тела:

Соседний документ HTML:

<!DOCTYPE html>
<html>
<head>
  <title>Chrome iFrame Tester</title>
  <script>
    function OnLoad() {
      try {
        window.sessionStorage['data'] = window.document.body.innerHTML;
      } catch {
        // no luck
      }
    }
  </script>
</head>
<body onload="OnLoad()">
  <div>This is Doc 1's content!</div>
</body>
</html>

Когда это запустится, мы должны увидеть содержимое HTML двух соседних документов, записанных в result div в index.html.

Когда я запускаю этот минимальный пример, я вижу, что содержимое успешно записано в sessionStorage, а затем в DOM для первого документа, но следующая попытка не удалась. Что я могу сделать, чтобы заставить его работать стабильно, и что здесь происходит, что оно терпит неудачу?

1 Ответ

2 голосов
/ 30 апреля 2019

Я не уверен, что является причиной странного поведения, так что, надеюсь, кто-то еще может дать некоторое представление о том, что именно здесь происходит.

А пока вот альтернативное решение с использованием window.postMessage:

index.html

<!DOCTYPE html>
<html>
<head>
  <title>Chrome iFrame Tester</title>
  <script src="iframe-load.js"></script>
</head>
<body onload="OnLoad()">
  <div id="result"></div>
</body>
</html>

iframe-load.js

var urls = ['file://C:/Users/afrench/Documents/Other/Misc%20Code/Chrome%20iFrame/Doc1.html', 
            'file://C:/Users/afrench/Documents/Other/Misc%20Code/Chrome%20iFrame/Doc2.html'];

window.addEventListener('message', event => {
  'use strict';

  var data = event.data;

  var container = document.getElementById('container');
  window.document.body.removeChild(container);

  if (data) {
    var resultContainer = document.getElementById('result');
    resultContainer.innerHTML += data;
  }

  if (urls.length > 0) {
    OnLoad();
  }
})

function OnLoad() {
  var url = urls.shift();

  if (url) {
    var container = document.createElement('div');
    container.id = 'container';
    container.style.visibility = 'hidden';
    window.document.body.appendChild(container);
    container.innerHTML = '<iframe src="' + url + '"></iframe>';
  }
}

Doc1.html

<!DOCTYPE html>
<html>
<head>
  <title>Chrome iFrame Tester</title>
  <script>
    function OnLoad() {
      window.parent.postMessage(window.document.body.innerHTML, '*');
    }
  </script>
</head>
<body onload="OnLoad()">
  <div>This is Doc 1's content!</div>
</body>
</html>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...