Выполнение скрипта после загрузки страницу javascript и jquery

Основы

XMLHttpRequest имеет два режима работы: синхронный и асинхронный.

Сначала рассмотрим асинхронный, так как в большинстве случаев используется именно он.

Чтобы сделать запрос, нам нужно выполнить три шага:

  1. Создать .

  2. Инициализировать его.

    Этот метод обычно вызывается сразу после . В него передаются основные параметры запроса:

    • – HTTP-метод. Обычно это или .
    • – URL, куда отправляется запрос: строка, может быть и объект URL.
    • – если указать , тогда запрос будет выполнен синхронно, это мы рассмотрим чуть позже.
    • , – логин и пароль для базовой HTTP-авторизации (если требуется).

    Заметим, что вызов , вопреки своему названию, не открывает соединение. Он лишь конфигурирует запрос, но непосредственно отсылается запрос только лишь после вызова .

  3. Послать запрос.

    Этот метод устанавливает соединение и отсылает запрос к серверу. Необязательный параметр содержит тело запроса.

    Некоторые типы запросов, такие как , не имеют тела. А некоторые, как, например, , используют , чтобы отправлять данные на сервер. Мы позже увидим примеры.

  4. Слушать события на , чтобы получить ответ.

    Три наиболее используемых события:

    • – происходит, когда получен какой-либо ответ, включая ответы с HTTP-ошибкой, например 404.
    • – когда запрос не может быть выполнен, например, нет соединения или невалидный URL.
    • – происходит периодически во время загрузки ответа, сообщает о прогрессе.

Вот полный пример. Код ниже загружает с сервера и сообщает о прогрессе:

После ответа сервера мы можем получить результат запроса в следующих свойствах :

Код состояния HTTP (число): , , и так далее, может быть в случае, если ошибка не связана с HTTP.
Сообщение о состоянии ответа HTTP (строка): обычно для , для , для , и так далее.
(в старом коде может встречаться как )
Тело ответа сервера.

Мы можем также указать таймаут – промежуток времени, который мы готовы ждать ответ:

Если запрос не успевает выполниться в установленное время, то он прерывается, и происходит событие .

URL с параметрами

Чтобы добавить к URL параметры, вида , и корректно закодировать их, можно использовать объект URL:

5 ответов

Лучший ответ

Если вы напрямую запускаете код с , вы откладываете рендеринг вашего браузера на время, необходимое для выполнения кода JavaScript.

Вы можете попробовать вставить свой код в вашего HTML-документа:

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

Теперь, если вы измените код, который будет выполняться для тела , страница будет обработана до , появится предупреждение:

3

jehna1
11 Мар 2016 в 22:59

Ожидание события onload гарантирует, что все ваши скрипты и ресурсы загружены

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

1

Hassan Khallouf
11 Мар 2016 в 22:54

сработает после завершения загрузки DOM. В вашем примере DOM не требуется. Однако следующий код не будет работать, если DOM еще не загружен:

Предполагая, что ваша страница содержит элемент с идентификатором , он сообщит свой текст.

1

rrowland
11 Мар 2016 в 22:53

Рассмотрим эти два блока кода:

В первом примере мы получим ошибку, потому что элемент, на который вы ссылаетесь, не найден при запуске скрипта — и поэтому вы пытаетесь получить из .

Во втором примере найдет элемент с идентификатором foo, потому что будет запущен только тогда, когда полная DOM будет загружена и, таким образом, элемент доступен.

2

baao
11 Мар 2016 в 22:56

Событие onload удобно, чтобы убедиться, что страница полностью загружена перед запуском скрипта. Для вашего примера выше это не имеет смысла, но если ваша страница все еще загружает элемент внизу, и вы пытаетесь вызвать его, то ничего не будет работать.

Я рекомендую использовать jQuery и использовать функцию ready. Таким образом, вы убедитесь, что ваша страница полностью загружена.

Если вы не хотите загружать запрос, просто поместите свой JavaScript внизу страницы. Это лучшая практика, обеспечивающая полную загрузку DOM.

1

Maximus
11 Мар 2016 в 22:58

Тип ответа

Мы можем использовать свойство , чтобы указать ожидаемый тип ответа:

  • (по умолчанию) – строка,
  • – строка,
  • – (для бинарных данных, смотрите в ArrayBuffer, бинарные массивы),
  • – (для бинарных данных, смотрите в Blob),
  • – XML-документ (может использовать XPath и другие XML-методы),
  • – JSON (парсится автоматически).

К примеру, давайте получим ответ в формате JSON:

В старом коде вы можете встретить свойства и даже .

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

Подробно о window.onload

  1. Иногда, происходит такое, что вы, вроде бы и написали все правильно, но скрипт… просто не работает. И непонятно почему.

    Одна из причин — это загрузка скрипта раньше, чем самой страницы. Ваш скрипт — тупо не видит код ниже себя.

    Для этого существует window.onload

    window — объект.

    onload — это «событие». Иногда, на просторах интернета можно встретить разное название для этого события, но «onload» — это «Event», а в переводе — это событие.

    Использовать window.onload можно самым простым способом, размещаем данный скрипт на странице и после загрузки страницы, вы увидите сообщение о том «скрипт выполнился после загрузки страницы»

    <script>

    window.onload = function() {

    alert(‘Страница загружена’);

    };

    </script>

    Если у вас подключенный скрипт, то теги <script> и </script> не нужны.

    window.onload = function() {

    здесь помещаем все, что угодно…

    };

    object может быть например body или window, естественно к этому объекту, сперва нужно обратиться.

    object.onload=function(){/**код**/};

    В качестве атрибута onload, возможно использование в HTML :

    <element onload=»myFunction»></element>

  2. Давайте попробуем создать эмуляцию window.onload, как это работает в реальном времени.

    Создадим скрипт и разместим его тут на странице:

    <script>

    window.onload = function() {

    alert(‘Страница загружена’);

    // к этому моменту страница загружена

    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);

    };

    </script>

    <img id=»img» src=»https://dwweb.ru/__a-data/__all_for_scripts/__examples/js/onload/onload.jpg»>

    Нажмите кнопку window.onload :
    window.onload

  3. Несколько вариантов для запуска вашего скрипта, при использовании JQuery

    $(window).load(function() {

    /** код запустится, когда страница будет полностью загружена на 100% **/

    });

    +

    //Вариант 1

    $(document).ready(function() {

    /** код запустится, когда будет готов DOM, исключая картинки **/

    // ваш код

    });

    //Вариант 2

    $(function() {

    /** код запустится, когда будет готов DOM, исключая картинки **/

    //ваш код

    });

    //Вариант 3

    $(document).on(‘ready’, function(){

    /** код запустится, когда будет готов DOM, исключая картинки **/

    //ваш код

    });

    //Вариант 4

    jQuery(document).ready(function(){

    /** код запустится, когда будет готов DOM, исключая картинки **/

    //ваш код

    });

    И!
    Не путаете window load jQuery с методом .

Последняя дата редактирования : 22.01.2021 00:06
//dwweb.ru/comments_1_5/include/img/hand_no_foto.png
no
no

HTML Теги

<!—…—><!DOCTYPE><a><abbr><acronym><address><applet><area><article><aside><audio><b><base><basefont><bdi><bdo><big><blockquote><body><br><button><canvas><caption><center><cite><code><col><colgroup><data><datalist><dd><del><details><dfn><dialog><dir><div><dl><dt><em><embed><fieldset><figcaption><figure><font><footer><form><frame><frameset><h1> — <h6><head><header><hr><html><i><iframe><img><input><ins><kbd><label><legend><li><link><main><map><mark><meta><meter><nav><noframes><noscript><object><ol><optgroup><option><output><p><param><picture><pre><progress><q><rp><rt><ruby><s><samp><script><section><select><small><source><span><strike><strong><style><sub><summary><sup><svg><table><tbody><td><template><textarea><tfoot><th><thead><time><title><tr><track><tt><u><ul><var><video>

window.onunload

When a visitor leaves the page, the event triggers on . We can do something there that doesn’t involve a delay, like closing related popup windows.

The notable exception is sending analytics.

Let’s say we gather data about how the page is used: mouse clicks, scrolls, viewed page areas, and so on.

Naturally, event is when the user leaves us, and we’d like to save the data on our server.

There exists a special method for such needs, described in the specification https://w3c.github.io/beacon/.

It sends the data in background. The transition to another page is not delayed: the browser leaves the page, but still performs .

Here’s how to use it:

  • The request is sent as POST.
  • We can send not only a string, but also forms and other formats, as described in the chapter Fetch: Basics, but usually it’s a stringified object.
  • The data is limited by 64kb.

When the request is finished, the browser probably has already left the document, so there’s no way to get server response (which is usually empty for analytics).

There’s also a flag for doing such “after-page-left” requests in fetch method for generic network requests. You can find more information in the chapter Fetch API.

If we want to cancel the transition to another page, we can’t do it here. But we can use another event – .

Пример использования

<!DOCTYPE html>
<html>
	<head>
		<title>Использование метода .load()</title>
		<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
		<script>
	$( document ).ready(function() {
	  $( "button" ).click(function() { // задаем функцию при нажатиии на элемент <button>
	    $( "div" ).load( "test.php", function( response, status, xhr ) { // с использованием AJAX запроса загружаем данные с сервера и размещаем, возвращенный HTML код внутри элемента <div>, и вызываем функцию обратного вызова
	      console.log( response ); // строка соответствующая данным, присланным от сервера
	      console.log( status ); // строка соответствующая статусу запроса
	      console.log( xhr.status ); // числовой код состояния ответа от сервера
	      console.log( xhr.statusText ); // сообщение о состоянии ответа
	    })
	  })
	});
		</script>
	</head>
	<body>
		<button>Клик</button>
		<br><br>
		<div></div>
	</body>
</html>

В этом примере с использованием jQuery метода .load() мы при нажатии на элемент <button> (кнопка) с использованием AJAX запроса загружаем данные с сервера и размещаем, возвращенный HTML код внутри элемента <div>. Загружаемый файл («test.php») содержит следующий HTML код:

<h1>Заголовок первого уровня</h1>
<p>Обычный параграф</p>

Кроме того, мы в качестве параметра метода .load() задаем функцию обратного вызова, которая выводит в консоль браузера следующую информацию:

  • Строка соответствующая данным, присланным от сервера.
  • Строка соответствующая статусу запроса (в нашем случае success).
  • Свойство status объекта XMLHTTPRequest, содержащее числовой код состояния ответа от сервера (в нашем случае 200)
  • Свойство statusText объекта XMLHTTPRequest, содержащее сообщение о состоянии ответа, которое вернулось от HTTP сервера (в нашем случае OK).

Результат нашего примера:

Пример использования jQuery метода .load()

Рассмотрим пример, в котором мы загрузим и вставим лишь необходимую часть документа, а не весь документ.

<!DOCTYPE html>
<html>
	<head>
		<title>Загрузка фрагмента документа методом .load()</title>
		<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
		<script>
	$( document ).ready(function() {
	  $( "button:first" ).click(function() { // задаем функцию при нажатиии на первый элемент <button>
	    $( ".content" ).load( "test.html" ) // полностью загружаем страницу
	  })
	  $( "button:last" ).click(function() { // задаем функцию при нажатиии на последний элемент <button>
	    $( ".content" ).load( "test.html .first" ) // загружаем фрагмент страницы (содержимое элемента с классом .first)
	  })
	});
		</script>
	</head>
	<body>
		<button>All</button>
		<button>First</button>
		<div class = "content"></div>
	</body>
</html>

В этом примере с использованием jQuery метода .load() мы при нажатии на определенный элемент <button> (кнопка) с использованием AJAX запроса загружаем данные с сервера и размещаем, возвращенный HTML код внутри элемента <div> с классом .content. При нажатии на первую кнопку мы загружаем весь документ, а при нажатии на вторую лишь его часть (элемент с классом .first ). Загружаемый файл («test.html») содержит следующий HTML код:

<!DOCTYPE html>
<html>
	<head>
		<meta charset = "UTF-8">
		<title>Тестовая страница</title>
	</head>
	<body>
		<div class = "first">
			Первый блок
			<script>
				alert("hello world");
			</script>
		</div>
		<div class = "second">
			Второй блок
		</div>
	</body>
</html>

Обратите внимание, на важный момент, что в первом случае (при загрузке всего документа) скрипт, размещенный в элементе с классом .first срабатывает, а во втором (при загрузке фрагмента документа) не срабатывает, не смотря на то, что скрипт размещен в этом фрагменте. Результат нашего примера:. Результат нашего примера:

Результат нашего примера:

Пример загрузки фрагмента документа методом .load()jQuery AJAX

Автоматическое заполнение браузерами

Firefox, Chrome и Opera автоматически заполняют поля форм для DOMContentLoaded. Например, если страница имеет форму с полями для ввода имени пользователя и пароля, а браузер запомнил их значения, DOMContentLoaded может попытаться автоматически их заполнить (если это одобрено пользователем).

Поэтому, кроме задержки до полной загрузки и выполнения скриптов, DOMContentLoaded может задерживаться и из-за автоматического заполнения полей форм. Вы могли сталкиваться с этим на некоторых сайтах: поля ввода логина / пароля не обновляются автоматически, и возникает задержка до полной загрузки страницы. На самом деле это задержка события DOMContentLoaded.

Одно из незначительных преимуществ использования атрибутов async и defer для внешних скриптов заключается в том, что они не блокируют DOMContentLoaded и позволяют избежать задержки, связанной с автоматическим заполнением форм.

More Examples

Example

Using onload on an <img> element. Alert «Image is loaded» immediately after
an image has been loaded:

<img src=»w3html.gif» onload=»loadImage()» width=»100″ height=»132″><script>function loadImage() {    alert(«Image is loaded»);}
</script>

Example

Using the onload event to deal with cookies (using «advanced» javascript):

<body onload=»checkCookies()»><p id=»demo»></p><script>
function checkCookies() {    var text = «»;    if (navigator.cookieEnabled == true) {        text = «Cookies are enabled.»;    } else {        text = «Cookies are not enabled.»;    }
   
document.getElementById(«demo»).innerHTML = text;}</script>

readyState

Что произойдет, если установить обработчик DOMContentLoaded после загрузки документа? Естественно, он никогда не запустится.

Бывают случаи, когда непонятно, готов ли документ. Например, внешний скрипт с атрибутом async загружается и запускается асинхронно. В зависимости от сети он может загружаться и выполняться до завершения загрузки документа или после этого. Поэтому необходимо знать текущее состояние документа.

Свойство document.readyState предоставляет такую информацию. Возможны три значения:

  • «» — документ загружается;
  • «interactive» — документ полностью считан;
  • «complete» — документ полностью считан и все ресурсы (например, изображения) загружены.

Так можно проверить значение document.readyState и настроить обработчик или выполнить код немедленно, как только он будет готов.

Например, следующим образом:

function work() { /*...*/ }
if (document.readyState == 'loading') {
  document.addEventListener('DOMContentLoaded', work);
} else {
  work();
}

Событие readystatechange запускается при изменении состояния. Можно выводить все эти состояния следующим образом:

// текущее состояние
console.log(document.readyState);

// выводим изменение состояния
document.addEventListener('readystatechange', () => console.log(document.readyState));

Событие readystatechange является альтернативным методом отслеживания состояния загрузки документа, оно было введено давно. В настоящее время оно редко используется, но рассмотрим его для полноты картины.

Как размещается readystatechange по отношению к другим событиям? Чтобы продемонстрировать порядок их срабатывания, ниже приводится пример с <iframe>, <img> и обработчиками, которые регистрируют события (JavaScript onload и другие):

<script>
  function log(text) { /* выводим время и сообщение */ }
  log('initial readyState:' + document.readyState);

  document.addEventListener('readystatechange', () => log('readyState:' + document.readyState));
  document.addEventListener('DOMContentLoaded', () => log('DOMContentLoaded'));

  window.onload = () => log('window onload');
</script>

<iframe src="iframe.html" onload="log('iframe onload')"></iframe>

<img src="http://en.js.cx/clipart/train.gif" id="img">
<script>
  img.onload = () => log('img onload');
</script>

Демо-версию можно найти на sandbox.

Стандартная последовательность событий:

  1. инициализация readyState:loading;
  2. readyState:interactive;
  3. DOMContentLoaded;
  4. iframe onload;
  5. readyState:complete;
  6. img onload;
  7. window onload JavaScript.

Цифры в квадратных скобках обозначают приблизительное время, когда это происходит. Реальное время немного больше, но события с одинаковой цифрой срабатывают примерно в одно и то же время (± несколько миллисекунд).

Document.readyState принимает состояние interactive непосредственно перед DOMContentLoaded. Эти два события фактически означают одно и то же.

Document.readyState завершается, когда загружаются все ресурсы (iframe и img). Мы видим, что это происходит примерно в то же время, что и img.onload (img — последний ресурс) и window.onload. Переключение на состояние complete означает то же, что и window.onload. Разница в том, что window.onload всегда запускается после всех других обработчиков load.

window.onbeforeunload

If a visitor initiated navigation away from the page or tries to close the window, the handler asks for additional confirmation.

If we cancel the event, the browser may ask the visitor if they are sure.

You can try it by running this code and then reloading the page:

For historical reasons, returning a non-empty string also counts as canceling the event. Some time ago browsers used show it as a message, but as the says, they shouldn’t.

Here’s an example:

The behavior was changed, because some webmasters abused this event handler by showing misleading and annoying messages. So right now old browsers still may show it as a message, but aside of that – there’s no way to customize the message shown to the user.

Crossorigin policy

There’s a rule: scripts from one site can’t access contents of the other site. So, e.g. a script at can’t read the user’s mailbox at .

Or, to be more precise, one origin (domain/port/protocol triplet) can’t access the content from another one. So even if we have a subdomain, or just another port, these are different origins with no access to each other.

This rule also affects resources from other domains.

If we’re using a script from another domain, and there’s an error in it, we can’t get error details.

For example, let’s take a script that consists of a single (bad) function call:

Now load it from the same site where it’s located:

We can see a good error report, like this:

Now let’s load the same script from another domain:

The report is different, like this:

Details may vary depending on the browser, but the idea is the same: any information about the internals of a script, including error stack traces, is hidden. Exactly because it’s from another domain.

Why do we need error details?

There are many services (and we can build our own) that listen for global errors using , save errors and provide an interface to access and analyze them. That’s great, as we can see real errors, triggered by our users. But if a script comes from another origin, then there’s not much information about errors in it, as we’ve just seen.

Similar cross-origin policy (CORS) is enforced for other types of resources as well.

To allow cross-origin access, the tag needs to have the attribute, plus the remote server must provide special headers.

There are three levels of cross-origin access:

  1. No attribute – access prohibited.
  2. – access allowed if the server responds with the header with or our origin. Browser does not send authorization information and cookies to remote server.
  3. – access allowed if the server sends back the header with our origin and . Browser sends authorization information and cookies to remote server.

Please note:

You can read more about cross-origin access in the chapter Fetch: Cross-Origin Requests. It describes the method for network requests, but the policy is exactly the same.

Such thing as “cookies” is out of our current scope, but you can read about them in the chapter Cookies, document.cookie.

In our case, we didn’t have any crossorigin attribute. So the cross-origin access was prohibited. Let’s add it.

We can choose between (no cookies sent, one server-side header needed) and (sends cookies too, two server-side headers needed).

If we don’t care about cookies, then is the way to go:

Now, assuming that the server provides an header, everything’s fine. We have the full error report.

DOMContentLoaded

Событие DOMContentLoaded происходит в объекте документа. Необходимо использовать addEventListener, чтобы отследить его:

document.addEventListener("DOMContentLoaded", ready);

Например:

<script>
  function ready() {
    alert('DOM is ready');

    // изображения еще не загрузились (если только не были сохранены в кэше), поэтому их размер 0x0
    alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`);
  }

  document.addEventListener("DOMContentLoaded", ready);
</script>

<img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">

В этом примере обработчик DOMContentLoaded запускается при загрузке документа (не при JavaScript onload), и не ждет полной загрузки страницы. Таким образом, предупреждение сообщает, что размер изображений равен нулю.

На первый взгляд событие DOMContentLoaded простое. Но есть несколько особенностей.

HTML Tags

<!—><!DOCTYPE><a><abbr><acronym><address><applet><area><article><aside><audio><b><base><basefont><bdi><bdo><big><blockquote><body><br><button><canvas><caption><center><cite><code><col><colgroup><data><datalist><dd><del><details><dfn><dialog><dir><div><dl><dt><em><embed><fieldset><figcaption><figure><font><footer><form><frame><frameset><h1> — <h6><head><header><hr><html><i><iframe><img><input><ins><kbd><label><legend><li><link><main><map><mark><meta><meter><nav><noframes><noscript><object><ol><optgroup><option><output><p><param><picture><pre><progress><q><rp><rt><ruby><s><samp><script><section><select><small><source><span><strike><strong><style><sub><summary><sup><svg><table><tbody><td><template><textarea><tfoot><th><thead><time><title><tr><track><tt><u><ul><var><video>

More Examples

Example

Using onload on an <img> element. Alert «Image is loaded» immediately after
an image has been loaded:

<img src=»w3javascript.gif» onload=»loadImage()» width=»100″ height=»132″><script>function loadImage() {  alert(«Image is loaded»);}
</script>

Example

Using the onload event to deal with cookies:

<body onload=»checkCookies()»><script>
function checkCookies() {  var text = «»;  if (navigator.cookieEnabled == true) {    text = «Cookies are enabled.»;  } else {     text = «Cookies are not enabled.»;
  }  document.getElementById(«demo»).innerHTML = text;}</script>

❮ DOM Events
❮ Event Object

Загрузка скриптов

Допустим, нам нужно загрузить сторонний скрипт и вызвать функцию, которая объявлена в этом скрипте.

Мы можем загрузить этот скрипт динамически:

let script = document.createElement('script');
script.src = "my.js";

document.head.append(script);

…Но как нам вызвать функцию, которая объявлена внутри того скрипта? Нам нужно подождать, пока скрипт загрузится, и только потом мы можем её вызвать.

script.onload

Главный помощник — это событие . Оно срабатывает после того, как скрипт был загружен и выполнен.

Например:

let script = document.createElement('script');

// мы можем загрузить любой скрипт с любого домена
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);

*!*
script.onload = function() {
  // в скрипте создаётся вспомогательная функция с именем "_"
  alert(_); // функция доступна
};
*!*

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

…А что если во время загрузки произошла ошибка? Например, такого скрипта нет (ошибка 404), или сервер был недоступен.

script.onerror

Ошибки, которые возникают во время загрузки скрипта, могут быть отслежены с помощью события .

Например, давайте запросим скрипт, которого не существует:

let script = document.createElement('script');
script.src = "https://example.com/404.js"; // такого файла не существует
document.head.append(script);

*!*
script.onerror = function() {
  alert("Error loading " + this.src); // Ошибка загрузки https://example.com/404.js
};
*!*

Обратите внимание, что мы не можем получить описание HTTP-ошибки. Мы не знаем, была ли это ошибка 404 или 500, или какая-то другая. Знаем только, что во время загрузки произошла ошибка

Знаем только, что во время загрузки произошла ошибка.

Ошибка в скрипте с другого источника

Есть правило: скрипты с одного сайта не могут получить доступ к содержимому другого сайта. Например, скрипт с не может прочитать почту пользователя на .

Или, если быть более точным, один источник (домен/порт/протокол) не может получить доступ к содержимому с другого источника. Даже поддомен или просто другой порт будут считаться разными источниками, не имеющими доступа друг к другу.

Это правило также касается ресурсов с других доменов.

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

Для примера давайте возьмём мини-скрипт , который состоит из одного-единственного вызова функции, которой не существует:

//  error.js
noSuchFunction();

Теперь загрузим этот скрипт с того же сайта, на котором он лежит:

<script>
window.onerror = function(message, url, line, col, errorObj) {
  alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="/article/onload-onerror/crossorigin/error.js"></script>

Мы видим нормальный отчёт об ошибке:

А теперь загрузим этот же скрипт с другого домена:

<script>
window.onerror = function(message, url, line, col, errorObj) {
  alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>

Отчёт отличается:

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

Зачем нам могут быть нужны детали ошибки?

Существует много сервисов (и мы можем сделать наш собственный), которые обрабатывают глобальные ошибки при помощи , сохраняют отчёт о них и предоставляют доступ к этому отчёту для анализа. Это здорово, потому что мы можем увидеть реальные ошибки, которые случились у наших пользователей. Но если скрипт — с другого домена, то информации об ошибках в нём почти нет, как мы только что видели.

Похожая кросс-доменная политика (CORS) внедрена и в отношении других ресурсов.

Чтобы разрешить кросс-доменный доступ, нам нужно поставить тегу атрибут , и, кроме того, удалённый сервер должен поставить специальные заголовки.

Существует три уровня кросс-доменного доступа:

  1. Атрибут отсутствует — доступ запрещён.
  2. — доступ разрешён, если сервер отвечает с заголовком со значениями или наш домен. Браузер не отправляет авторизационную информацию и куки на удалённый сервер.
  3. — доступ разрешён, если сервер отвечает с заголовками со значением наш домен и . Браузер отправляет авторизационную информацию и куки на удалённый сервер.

В нашем случае атрибут отсутствовал. Поэтому кросс-доменный доступ был запрещён. Давайте добавим его.

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

Если куки нас не волнуют, тогда смело выбираем :

<script>
window.onerror = function(message, url, line, col, errorObj) {
  alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script *!*crossorigin="anonymous"*/!* src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>

Теперь при условии, что сервер предоставил заголовок , всё хорошо. У нас есть полный отчёт по ошибкам.

Итого

Чтобы вызвать метод или получить содержимое из другого окна, нам, во-первых, необходимо иметь ссылку на него.

Для всплывающих окон (попапов) доступны ссылки в обе стороны:

  • При открытии окна: открывает новое окно и возвращает ссылку на него,
  • Изнутри открытого окна: – ссылка на открывающее окно.

Для ифреймов мы можем иметь доступ к родителям/потомкам, используя:

  • – коллекция объектов вложенных ифреймов,
  • , – это ссылки на родительское окно и окно самого верхнего уровня,
  • – это объект внутри тега .

Если окна имеют одинаковый источник (протокол, домен, порт), то они могут делать друг с другом всё, что угодно.

В противном случае возможны только следующие действия:

  • Изменение свойства location другого окна (доступ только на запись).
  • Отправить туда сообщение.

Исключения:

  • Окна, которые имеют общий домен второго уровня: и . Установка свойства в обоих окнах переведёт их в состояние «Одинакового источника».
  • Если у ифрейма установлен атрибут , это принудительно переведёт окна в состояние «разных источников», если не установить в атрибут значение . Это можно использовать для запуска ненадёжного кода в ифрейме с того же сайта.

Метод позволяет общаться двум окнам с любыми источниками:

  1. Отправитель вызывает .

  2. Если не , тогда браузер проверяет имеет ли источник .

  3. Если это так, тогда вызывает событие со специальными свойствами:

    • – источник окна отправителя (например, )
    • – ссылка на окно отправитель.
    • – данные, может быть объектом везде, кроме IE (в IE только строки).

    В окне-получателе следует добавить обработчик для этого события с помощью метода .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector