Подтвердить что ты не робот

Мой инъекционный <script> запускается после javascript целевой страницы, несмотря на использование run_at: document_start?

У меня возникла проблема с порядком выполнения javascript, когда я использую содержимое script для вставки некоторого javascript в HTML-страницу:

Это моя HTML-страница, которую я использую для тестирования, test.html:

<html><head>    
<title>Test Page</title></head>
  <body>
    <script>
      console.log("In page");
    </script>
  </body>
</html>


Это javascript, который я использую для добавления дополнительного кода в HTML-страницу, injector.js:

var s = document.createElement("script");
s.src = chrome.extension.getURL("inject.js");
document.documentElement.appendChild(s);
console.log("Inject finished");


И это содержимое введенных script, inject.js:

console.log("Inside inject.js");


И, наконец, это мой manifest.json:

  "web_accessible_resources": [
    "inject.js"
  ],
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["/injector.js"],
      "run_at": "document_start"
    }
  ]


Теперь, когда я открываю test.html, это то, что я получил в своей консоли:

Inject finished
In page
Inside inject.js


Мой вопрос: почему In page распечатывается до Inside inject.js? Не предполагается ли запуск inject.js первым, так как я установил run_at в document_start?

Если это по дизайну, есть ли способ убедиться, что содержимое внутри inject.js выполняется до script внутри HTML-страницы , не изменяя ничего внутри HTML-страницы

Настройка атрибута async на false до appendChild не работает, поскольку он используется для упорядочения между внешними скриптами, а не между внешними скриптами и страницей script.

Кстати, я тестирую это на Chrome 27.0.1453.9

4b9b3361

Ответ 1

Вложенные скрипты с атрибутами src выполняются асинхронно в Chrome.
Рассмотрим этот HTML файл:

<html><head>
    <title>Chrome early script inject, Test Page</title>
    <script>
        var s = document.createElement ("script");
        s.src = "localInject1.js";
        document.documentElement.appendChild (s);
    </script>
</head>
<body>
<p>See the console.</p>
<script src="localInject2.js"></script>
<script> console.log("In page: ", new Date().getTime()); </script>
</body>
</html>

где localInject1.js справедливо:

console.log("In page script 1: ", new Date().getTime());

и localInject2.js:

console.log("In page script 2: ", new Date().getTime());


Номинально консоль должна показывать:

In page script 1:   ...
In page script 2:   ...
In page:   ...


Но часто, и особенно при перезагрузке без кэша, вы увидите:

In page script 2:   ...
In page:   ...
In page script 1:   ...


Настройка s.async = false; не имеет значения.


Я не уверен, что это ошибка или нет. Firefox также выводит скрипты из строя, но кажется более последовательным. Кажется, что не существует любых соответствующих ошибок Chrome, и спецификации мне неясны.


Работа вокруг:

Сценарии с кодом, установленным textContent, а не файл, связанный с src, выполняются немедленно, как и следовало ожидать.
Например, если вы изменили injector.js на:

var s = document.createElement ("script");
s.src = chrome.extension.getURL ("inject.js");
document.documentElement.appendChild (s);

var s = document.createElement ('script');
s.textContent = 'console.log ("Text runs correctly!", new Date().getTime() );';
document.documentElement.appendChild (s);

console.log("Inject finished", new Date().getTime() );

вы увидите:

Text runs correctly! ...
Inject finished ...
In page
Inside inject.js


По общему признанию, это может быть болью в содержимом script, но это может быть все, что вы можете сделать (в Chrome), пока эта проблема не будет решена поставщиками W3C и браузеров.

Ответ 2

Теги JavaScript script не блокируют выполнение (к счастью!). Если вы хотите получить необходимую функциональность (ленивая загрузка), вам нужно сделать что-то вроде следующего:

function loadScript(scriptName, callback) {
   var sTag = document.createElement("script");
   sTag.src = scriptName;
   sTag.onreadystatechange = sTag.onload = function() {
    var state = s.readyState;

    if (!state || /loaded|complete/.test(state)) {
        callback();
    }
  };
 }

Это приведет к срабатыванию функции обратного вызова при загрузке тега script. Оттуда загрузите все и убедитесь, что каждый обратный вызов обработан, а затем запустите события загрузки страницы в здравом рассудке, что у вас есть каждая библиотека, в которой вы нуждаетесь.

Ответ 3

Когда вы добавляете javascript на такую ​​страницу, он приходит асинхронно. Если у вас на самом деле есть тег <script> с самого начала, он будет синхронным и будет работать в правильном порядке.

Вид сбоя, но поскольку он асинхронен, ваш код будет продолжать выполняться, пока загружается другой файл script.

Чтобы узнать, когда закончится script, вам нужно обработать событие для script - проще всего использовать функцию jQuery getScript, которая предоставляет вам аргумент обратного вызова.

Ответ 4

Существуют целые библиотеки, предназначенные для достижения того, что вы пытаетесь сделать, поскольку каждый браузер, похоже, добавляет свою собственную долю ошибок. Посмотрите на что-то вроде HeadJS или уже используете jQuery, что сказал Джо.