Window.onload против $ (document) .ready ()
Содержание:
- Window.onunload¶
- readyState
- More Examples
- Размещение скрипта
- DOMContentLoaded и стили
- Подставка первого скрипта
- Лучшая техника
- HTML Reference
- HTML Tags
- window.onbeforeunload
- DOMContentLoaded¶
- Несколько слов об async и defer
- JavaScript
- Пример на YUI 3
- window.onunload
- Автоматическое заполнение браузерами
- window.onbeforeunload
- HTML Tags
- DOMContentLoaded
Window.onunload¶
The unload event triggers on the window when a visitor leaves the page. You can do there something that doesn’t include a delay (for example, closing related popup window). Sending analytics is considered a notable exception.
Imagine, you want to gather data about how the page is used: scrolls, mouse clicks, and so on. As a rule, the unload event is when the user leaves the page, and you want to save the data on the server. A unique navigator.sendBeacon(url, data) method exists for such needs. It can send the data to the background. Also, there is no delay in the transition to another page still performing sendBeacon.
Here is an example of using sendBeacon:
So, in the example above:
- The request is forwarded as POST.
- It is possible to send not only a string but also forms and other formats.
- There is a data limit: 64kb.
Once the sendBeacon request is over, the browser has probably left the document. Therefore, there is no way of getting server response (for analytics, it’s usually empty).
Also, you can use keepalive to perform “after-page-left” requests in the fetch method for generic network requests.
For canceling the transition to another page, you can use another event: onbeforeunload.
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.
Стандартная последовательность событий:
- инициализация readyState:loading;
- readyState:interactive;
- DOMContentLoaded;
- iframe onload;
- readyState:complete;
- img onload;
- window onload JavaScript.
Цифры в квадратных скобках обозначают приблизительное время, когда это происходит. Реальное время немного больше, но события с одинаковой цифрой срабатывают примерно в одно и то же время (± несколько миллисекунд).
Document.readyState принимает состояние interactive непосредственно перед DOMContentLoaded. Эти два события фактически означают одно и то же.
Document.readyState завершается, когда загружаются все ресурсы (iframe и img). Мы видим, что это происходит примерно в то же время, что и img.onload (img — последний ресурс) и window.onload. Переключение на состояние complete означает то же, что и window.onload. Разница в том, что window.onload всегда запускается после всех других обработчиков load.
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>
Размещение скрипта
Вы заметите, что я упомянул лучшую практику размещения этого кода в конце страницы, прямо внутри закрывающего тега. Это совет, который существует уже некоторое время, и я все еще рекомендую его, даже при использовании этой техники. Причина в том, что вам гарантировано, что все элементы DOM, которые вам могут понадобиться, уже присутствуют на странице. Загрузка ваших сценариев ранее может привести к проблемам с синхронизацией, когда вам нужно будет беспокоиться об использовании или о каком-либо другом методе, чтобы определить, когда DOM готов к использованию. Включив этот код внизу страницы, вы можете быть уверены, что DOM готов к работе, и вам больше не придется откладывать инициализацию.
DOMContentLoaded и стили
Внешние таблицы стилей не влияют на DOM, поэтому DOMContentLoaded не ждет их загрузки. Но есть одно исключение: если скрипт размещен после подключения стилей, то он должен ждать загрузки и обработки CSS:
<link type="text/css" rel="stylesheet" href="style.css"> <script> // скрипт не будет выполняться до тех пор, пока не загружены таблицы стиле alert(getComputedStyle(document.body).marginTop); </script>
Причина этого заключается в том, что скрипту могут понадобиться координаты и другие, зависящие от стиля свойства элементов, как в приведенном выше примере. Естественно, он должен ждать загрузки CSS.
Поскольку DOMContentLoaded ожидает загрузки скриптов (document onload JavaScript), он должен дождаться и загрузки стилей.
Подставка первого скрипта
Несколько комментаторов правильно указали, что эту технику можно дополнительно оптимизировать, переместив исходную функцию в строку вместо сохранения ее во внешнем файле. Как правило, мне нравится хранить JavaScript вне кода страницы для удобства сопровождения. Я также ожидал, что исходный код JavaScript на странице будет больше, чем просто эта функция по той или иной причине. Если у вас может быть какая-то автоматизация для внедрения этого на вашу страницу в виде встроенного сценария, я полностью за это! Ключевой момент – убедидесь, что первый встроенный скрипт достаточно мал, чтобы производительность во время выполнения не влияла на загрузку страниц.
Лучшая техника
Подумав об этом и поэкспериментировав, я пришел к выводу, что есть только один лучший способ загрузки JavaScript без блокировки:
- Создайте два файла JavaScript. Первый содержит только код, необходимый для динамической загрузки JavaScript, второй содержит все остальное, что необходимо для начального уровня интерактивности на странице.
- Включите первый файл JavaScript с тегом внизу страницы, прямо внутри .
- Создайте второй тег, который вызывает функцию для загрузки второго файла JavaScript и содержит любой дополнительный код инициализации.
Это оно! Там действительно нет необходимости делать что-либо еще. Главное, чтобы у вас было только два JavaScript и сделайте первый как можно меньше. Например, первый файл .js может просто содержать эту функцию:
Это небольшой объем кода для загрузки, так что он будет загружаться невероятно быстро (особенно при сжатии).
Фактический код на вашей странице в конечном итоге выглядит так:
Ключом ко всей этой технике является наличие всего двух файлов JavaScript, поэтому второй содержит все, что необходимо для инициализации страницы. Что если вашей странице требуется более двух файлов? Затем вы должны объединить свои файлы во время сборки (используя что-то вроде Sprockets ) или во время выполнения (используя что-то вроде mod_concat или комбинированный обработчик).). Теперь загрузка страницы должна произойти очень быстро, за счет правильной инициализации. У каждого дополнительного HTTP-запроса есть издержки, и вам нужно будет заботиться о последовательности загрузок, чтобы код выполнялся в правильном порядке. Имея всего два файла, вы устраняете большую проблему, касающуюся того, какой файл загружается и выполняется первым, а также исключаете ненужные HTTP-запросы.
HTML Reference
HTML by AlphabetHTML by CategoryHTML Browser SupportHTML AttributesHTML Global AttributesHTML EventsHTML ColorsHTML CanvasHTML Audio/VideoHTML Character SetsHTML DoctypesHTML URL EncodeHTML Language CodesHTML Country CodesHTTP MessagesHTTP MethodsPX to EM ConverterKeyboard Shortcuts
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>
<wbr>
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.
DOMContentLoaded¶
This event occurs on the document object.
The addEventListener should be used to catch it, like this:
Here is an extensive example of using addEventListener:
Try it Yourself »
In the example above, the DOMContentLoaded runs once the document is loaded. So, it is capable of seeing all the elements, including <img>.
But, note that it never waits for the image to load. Hence, the alert will show zero sizes.
The DOMContentLoaded event looks very simple at first sight. But, the event comes when the DOM tree is ready.
However, few peculiarities exist that we are going to cover further.
DOMContentLoaded and Scripts
Once the document processes an HTML-document and passes through a <script> tag, it should execute before continuing to set up the DOM. It’s like a precaution because scripts might want to modify the DOM, and, moreover, document.write into it. Therefore, the DOMContentLoaded should wait.
So, the DOMContentLoaded event occurs after scripts like this:
Try it Yourself »
As you can notice from the example above, first comes “Library loaded…” , only then “DOM ready”.
Please, note that there are exceptions to this rule. That is to say, the scripts with async attribute never block DOMContentLoaded. The scripts that are created dynamically using document.createElement('script') and added to the webpage after, don’t block this event, either.
DOMContentLoaded and Styles
The DOM is not affected by external style sheets, so DOMContentLoaded doesn’t wait for them.
But there is a drawback here. If there is a script after the style, then the script shall wait till the stylesheet is loading, like this:
Try it Yourself »
That happens because the script might want to get coordinates or other style-dependant properties. So, it should wait for the style to load. As though DOMContentLoaded waits for the scripts, it will wait for the styles before them, too.
Built-in Browser Autofill
Chrome, Opera and Firefox can autofill forms on DOMContentLoaded. For example, if there is a page form with a login and password, and the browser remembered the values, then it might try to autofill them on DOMContentLoaded (it should be approved by the user).
Moreover, if DOMContentLoaded is suspended by the long-load scripts, the autofill should also wait. In some sites (in case of using browser autofill) the fields of login and password don’t get auto-filled at once. There is a delay until the page is completely loaded. That’s the delay till the DOMContentLoaded event.
Несколько слов об async и defer
Атрибуты async и defer в window onload JavaScript используются только для внешних скриптов. Они игнорируются, если нет подключения через src.
Оба атрибута указывают браузеру, что он может продолжать обрабатывать страницу и загружать скрипты «в фоновом режиме». А затем запускать скрипт после его полной загрузки. Таким образом, скрипт не блокирует создание DOM и отображение страниц.
Между этими атрибутами есть два отличия.
async | Defer | |
Порядок | Скрипты с атрибутом async выполняются в том порядке, в котором они загружаются. Порядок, в котором они указаны в документе, не имеет значения — скрипт, загруженный первым, выполняется первым. | Скрипты с атрибутом defer всегда выполняются в соответствии с порядком, в котором они расположены в документе. |
DOMContentLoaded | Скрипты с атрибутом async могут загружаться и выполняться, пока документ еще не загружен полностью. Это происходит, когда скрипты являются небольшими или кэшируются, а документ достаточно объемен. | Скрипты с атрибутом defer выполняются после того, как документ будет полностью загружен и обработан (если необходимо они ожидают завершения процесса), сразу после события DOMContentLoaded. |
Атрибут async используется для полностью независимых скриптов.
JavaScript
JS Array
concat()
constructor
copyWithin()
entries()
every()
fill()
filter()
find()
findIndex()
forEach()
from()
includes()
indexOf()
isArray()
join()
keys()
length
lastIndexOf()
map()
pop()
prototype
push()
reduce()
reduceRight()
reverse()
shift()
slice()
some()
sort()
splice()
toString()
unshift()
valueOf()
JS Boolean
constructor
prototype
toString()
valueOf()
JS Classes
constructor()
extends
static
super
JS Date
constructor
getDate()
getDay()
getFullYear()
getHours()
getMilliseconds()
getMinutes()
getMonth()
getSeconds()
getTime()
getTimezoneOffset()
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
now()
parse()
prototype
setDate()
setFullYear()
setHours()
setMilliseconds()
setMinutes()
setMonth()
setSeconds()
setTime()
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
toDateString()
toISOString()
toJSON()
toLocaleDateString()
toLocaleTimeString()
toLocaleString()
toString()
toTimeString()
toUTCString()
UTC()
valueOf()
JS Error
name
message
JS Global
decodeURI()
decodeURIComponent()
encodeURI()
encodeURIComponent()
escape()
eval()
Infinity
isFinite()
isNaN()
NaN
Number()
parseFloat()
parseInt()
String()
undefined
unescape()
JS JSON
parse()
stringify()
JS Math
abs()
acos()
acosh()
asin()
asinh()
atan()
atan2()
atanh()
cbrt()
ceil()
clz32()
cos()
cosh()
E
exp()
expm1()
floor()
fround()
LN2
LN10
log()
log10()
log1p()
log2()
LOG2E
LOG10E
max()
min()
PI
pow()
random()
round()
sign()
sin()
sqrt()
SQRT1_2
SQRT2
tan()
tanh()
trunc()
JS Number
constructor
isFinite()
isInteger()
isNaN()
isSafeInteger()
MAX_VALUE
MIN_VALUE
NEGATIVE_INFINITY
NaN
POSITIVE_INFINITY
prototype
toExponential()
toFixed()
toLocaleString()
toPrecision()
toString()
valueOf()
JS OperatorsJS RegExp
constructor
compile()
exec()
g
global
i
ignoreCase
lastIndex
m
multiline
n+
n*
n?
n{X}
n{X,Y}
n{X,}
n$
^n
?=n
?!n
source
test()
toString()
(x|y)
.
\w
\W
\d
\D
\s
\S
\b
\B
\0
\n
\f
\r
\t
\v
\xxx
\xdd
\uxxxx
JS Statements
break
class
continue
debugger
do…while
for
for…in
for…of
function
if…else
return
switch
throw
try…catch
var
while
JS String
charAt()
charCodeAt()
concat()
constructor
endsWith()
fromCharCode()
includes()
indexOf()
lastIndexOf()
length
localeCompare()
match()
prototype
repeat()
replace()
search()
slice()
split()
startsWith()
substr()
substring()
toLocaleLowerCase()
toLocaleUpperCase()
toLowerCase()
toString()
toUpperCase()
trim()
valueOf()
Пример на YUI 3
YUI 3 разработан вокруг этой самой предпосылки. Вы можете начать с загрузки файла yui.js, а затем использовать встроенный компонент Loader для динамической загрузки остальной части библиотеки YUI. Например:
Этот код сначала загружается в исходный файл YUI, затем создает новый экземпляр объекта и указывает, что компонент «узел» необходим. За кулисами YUI создает URL со всеми зависимостями для «узла», динамически загружает его, а затем вызывает функцию обратного вызова после завершения. Крутая вещь в подходе YUI 3 заключается в том, что вам не нужно беспокоиться о статическом включении URL для JavaScript, просто укажите, какие компоненты вам нужны, и библиотека определит правильный URL для загрузки ( ).
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 – .
Автоматическое заполнение браузерами
Firefox, Chrome и Opera автоматически заполняют поля форм для DOMContentLoaded. Например, если страница имеет форму с полями для ввода имени пользователя и пароля, а браузер запомнил их значения, DOMContentLoaded может попытаться автоматически их заполнить (если это одобрено пользователем).
Поэтому, кроме задержки до полной загрузки и выполнения скриптов, DOMContentLoaded может задерживаться и из-за автоматического заполнения полей форм. Вы могли сталкиваться с этим на некоторых сайтах: поля ввода логина / пароля не обновляются автоматически, и возникает задержка до полной загрузки страницы. На самом деле это задержка события DOMContentLoaded.
Одно из незначительных преимуществ использования атрибутов async и defer для внешних скриптов заключается в том, что они не блокируют DOMContentLoaded и позволяют избежать задержки, связанной с автоматическим заполнением форм.
window.onbeforeunload
Если посетитель покидает страницу или пытается закрыть окно, обработчик beforeunload может запросить дополнительное подтверждение. Этот обработчик возвращает строку с вопросом. Браузер отобразит ее.
Например:
window.onbeforeunload = function() { return "Некоторые изменения не были сохранены. Вы все равно желаете покинуть страницу?"; };
Некоторые браузеры, такие как Chrome и Firefox, игнорируют заданное значение и отображают собственное сообщение. Делается это из соображений безопасности, чтобы защитить пользователя от мошеннических и хакерских сообщений при наступлении события JavaScript onload.
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>
DOMContentLoaded
The event happens on the object.
We must use to catch it:
For instance:
In the example the handler runs when the document is loaded, so it can see all the elements, including below.
But it doesn’t wait for the image to load. So shows zero sizes.
At the first sight event is very simple. The DOM tree is ready – here’s the event. There are few peculiarities though.
When the browser processes an HTML-document and comes across a tag, it needs to execute before continuing building the DOM. That’s a precaution, as scripts may want to modify DOM, and even into it, so has to wait.
So DOMContentLoaded definitely happens after such scripts:
In the example above, we first see “Library loaded…”, and then “DOM ready!” (all scripts are executed).
Scripts with , or don’t block DOMContentLoaded
Script attributes and , that we’ll cover a bit later, don’t block DOMContentLoaded. JavaScript modules behave like , they don’t block it too.
So here we’re talking about “regular” scripts, like , or .
External style sheets don’t affect DOM, so does not wait for them.
But there’s a pitfall. If we have a script after the style, then that script must wait until the stylesheet loads:
The reason is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above. Naturally, it has to wait for styles to load.
As waits for scripts, it now waits for styles before them as well.
Firefox, Chrome and Opera autofill forms on .
For instance, if the page has a form with login and password, and the browser remembered the values, then on it may try to autofill them (if approved by the user).
So if is postponed by long-loading scripts, then autofill also awaits. You probably saw that on some sites (if you use browser autofill) – the login/password fields don’t get autofilled immediately, but there’s a delay till the page fully loads. That’s actually the delay until the event.