Ð ÑовÑеменнÑÑ ÑайÑÐ°Ñ ÑкÑипÑÑ Ð¾Ð±ÑÑно «ÑÑжелее», Ñем HTML: они веÑÑÑ Ð±Ð¾Ð»ÑÑе, долÑÑе обÑабаÑÑваÑÑÑÑ.
Ðогда бÑаÑÐ·ÐµÑ Ð·Ð°Ð³ÑÑÐ¶Ð°ÐµÑ HTML и доÑ
Ð¾Ð´Ð¸Ñ Ð´Ð¾ Ñега <script>...</script>, он не Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑодолжаÑÑ ÑÑÑоиÑÑ DOM. Ðн должен ÑнаÑала вÑполниÑÑ ÑкÑипÑ. То же Ñамое пÑоиÑÑ
Ð¾Ð´Ð¸Ñ Ð¸ Ñ Ð²Ð½ÐµÑними ÑкÑипÑами <script src="..."></script>: бÑаÑÐ·ÐµÑ Ð´Ð¾Ð»Ð¶ÐµÐ½ подождаÑÑ, пока загÑÑзиÑÑÑ ÑкÑипÑ, вÑполниÑÑ ÐµÐ³Ð¾, и ÑолÑко заÑем обÑабоÑаÑÑ Ð¾ÑÑалÑнÑÑ ÑÑÑаниÑÑ.
ÐÑо ведÑÑ Ðº двÑм важнÑм пÑоблемам:
- СкÑипÑÑ Ð½Ðµ видÑÑ DOM-ÑлеменÑÑ Ð½Ð¸Ð¶Ðµ ÑебÑ, поÑÑÐ¾Ð¼Ñ Ðº ним нелÑÐ·Ñ Ð´Ð¾Ð±Ð°Ð²Ð¸ÑÑ Ð¾Ð±ÑабоÑÑики и Ñ.д.
- ÐÑли ввеÑÑ Ñ ÑÑÑаниÑÑ Ð¾Ð±ÑÑмнÑй ÑкÑипÑ, он «блокиÑÑеÑ» ÑÑÑаниÑÑ. ÐолÑзоваÑели не видÑÑ ÑодеÑжимое ÑÑÑаниÑÑ, пока он не загÑÑзиÑÑÑ Ð¸ не запÑÑÑиÑÑÑ:
<p>...ÑодеÑжимое пеÑед ÑкÑипÑом...</p>
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- ÐÑо не оÑобÑазиÑÑÑ, пока ÑкÑÐ¸Ð¿Ñ Ð½Ðµ загÑÑзиÑÑÑ -->
<p>...ÑодеÑжимое поÑле ÑкÑипÑа...</p>
ÐонеÑно, еÑÑÑ Ð¿ÑÑи, как ÑÑо обойÑи. ÐапÑимеÑ, Ð¼Ñ Ð¼Ð¾Ð¶ÐµÐ¼ помеÑÑиÑÑ ÑкÑÐ¸Ð¿Ñ Ð²Ð½Ð¸Ð·Ñ ÑÑÑаниÑÑ. Тогда он ÑÐ¼Ð¾Ð¶ÐµÑ Ð²Ð¸Ð´ÐµÑÑ ÑлеменÑÑ Ð½Ð°Ð´ ним и не бÑÐ´ÐµÑ Ð¿ÑепÑÑÑÑвоваÑÑ Ð¾ÑобÑÐ°Ð¶ÐµÐ½Ð¸Ñ ÑодеÑжимого ÑÑÑаниÑÑ:
<body>
...вÑÑ ÑодеÑжимое над ÑкÑипÑом...
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
</body>
Ðо ÑÑо ÑеÑение далеко Ð¾Ñ Ð¸Ð´ÐµÐ°Ð»Ñного. ÐапÑимеÑ, бÑаÑÐ·ÐµÑ Ð·Ð°Ð¼ÐµÑÐ°ÐµÑ ÑкÑÐ¸Ð¿Ñ (и Ð¼Ð¾Ð¶ÐµÑ Ð½Ð°ÑаÑÑ Ð·Ð°Ð³ÑÑжаÑÑ ÐµÐ³Ð¾) ÑолÑко поÑле Ñого, как он полноÑÑÑÑ Ð·Ð°Ð³ÑÑзил HTML-докÑменÑ. Ð ÑлÑÑае Ñ Ð´Ð»Ð¸Ð½Ð½Ñми HTML-ÑÑÑаниÑами ÑÑо Ð¼Ð¾Ð¶ÐµÑ ÑоздаÑÑ Ð·Ð°Ð¼ÐµÑнÑÑ Ð·Ð°Ð´ÐµÑжкÑ.
Такие веÑи незамеÑÐ½Ñ Ð»ÑдÑм, Ñ ÐºÐ¾Ð³Ð¾ оÑÐµÐ½Ñ Ð±ÑÑÑÑое Ñоединение, но много кÑо в миÑе Ð¸Ð¼ÐµÐµÑ Ð¼ÐµÐ´Ð»ÐµÐ½Ð½Ð¾Ðµ подклÑÑение к инÑеÑнеÑÑ Ð¸Ð»Ð¸ иÑполÑзÑÐµÑ Ð½Ðµ Ñакой Ñ Ð¾ÑоÑий мобилÑнÑй инÑеÑнеÑ.
Ð ÑÑаÑÑÑÑ, еÑÑÑ Ð´Ð²Ð° аÑÑибÑÑа Ñега <script>, коÑоÑÑе ÑеÑаÑÑ Ð½Ð°ÑÑ Ð¿ÑоблемÑ: defer и async.
defer
ÐÑÑибÑÑ defer ÑообÑÐ°ÐµÑ Ð±ÑаÑзеÑÑ, ÑÑо он должен пÑодолжаÑÑ Ð¾Ð±ÑабаÑÑваÑÑ ÑÑÑаниÑÑ Ð¸ загÑÑжаÑÑ ÑкÑÐ¸Ð¿Ñ Ð² Ñоновом Ñежиме, а заÑем запÑÑÑиÑÑ ÑÑÐ¾Ñ ÑкÑипÑ, когда DOM деÑево бÑÐ´ÐµÑ Ð¿Ð¾Ð»Ð½Ð¾ÑÑÑÑ Ð¿Ð¾ÑÑÑоено.
ÐÐ¾Ñ ÑÐ¾Ñ Ð¶Ðµ пÑимеÑ, ÑÑо и вÑÑе, но Ñ defer:
<p>...ÑодеÑжимое пеÑед ÑкÑипÑом...</p>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- оÑобÑажаеÑÑÑ ÑÑÐ°Ð·Ñ Ð¶Ðµ -->
<p>...ÑодеÑжимое поÑле ÑкÑипÑа...</p>
- СкÑипÑÑ Ñ
deferникогда не блокиÑÑÑÑ ÑÑÑаниÑÑ. - СкÑипÑÑ Ñ
deferвÑегда вÑполнÑÑÑÑÑ, когда деÑево DOM гоÑово, но до ÑобÑÑиÑDOMContentLoaded.
СледÑÑÑий пÑÐ¸Ð¼ÐµÑ ÑÑо показÑваеÑ:
<p>...ÑодеÑжимое до ÑкÑипÑа...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("ÐеÑево DOM гоÑово поÑле ÑкÑипÑа Ñ 'defer'!"));
</script>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script> // (2)
<p>...ÑодеÑжимое поÑле ÑкÑипÑа...</p>
- СодеÑжимое ÑÑÑаниÑÑ Ð¾ÑобÑазиÑÑÑ Ð¼Ð³Ð½Ð¾Ð²ÐµÐ½Ð½Ð¾.
- СобÑÑие
DOMContentLoadedподождÑÑ Ð¾ÑложеннÑй ÑкÑипÑ. Ðно бÑÐ´ÐµÑ ÑгенеÑиÑовано, ÑолÑко когда ÑкÑипÑ(2)бÑÐ´ÐµÑ Ð·Ð°Ð³ÑÑжен и вÑполнен.
ÐÑложеннÑе Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ defer ÑкÑипÑÑ ÑоÑ
ÑанÑÑÑ Ð¿Ð¾ÑÑдок оÑноÑиÑелÑно дÑÑг дÑÑга, как и обÑÑнÑе ÑкÑипÑÑ.
ÐопÑÑÑим, Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð´Ð²Ð° ÑкÑипÑа c defer: small.js и long.js:
<script defer src="https://javascript.info/article/script-async-defer/long.js"></script>
<script defer src="https://javascript.info/article/script-async-defer/small.js"></script>
ÐÑаÑзеÑÑ ÑканиÑÑÑÑ ÑÑÑаниÑÑ Ð½Ð° пÑÐµÐ´Ð¼ÐµÑ ÑкÑипÑов и загÑÑжаÑÑ Ð¸Ñ
паÑаллелÑно в ÑелÑÑ
ÑвелиÑÐµÐ½Ð¸Ñ Ð¿ÑоизводиÑелÑноÑÑи. ÐоÑÑÐ¾Ð¼Ñ Ð¸ в пÑимеÑе вÑÑе оба ÑкÑипÑа ÑкаÑиваÑÑÑÑ Ð¿Ð°ÑаллелÑно. small.js ÑкоÑее вÑего загÑÑзиÑÑÑ Ð¿ÐµÑвÑм.
â¦Ðо defer не ÑолÑко говоÑÐ¸Ñ Ð±ÑаÑзеÑÑ Â«Ð½Ðµ блокиÑоваÑÑ ÑендеÑинг», он Ñакже обеÑпеÑÐ¸Ð²Ð°ÐµÑ Ð¿ÑавилÑнÑÑ Ð¿Ð¾ÑледоваÑелÑноÑÑÑ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÑкÑипÑов. Ðаже еÑли small.js загÑÑзиÑÑÑ Ð¿ÐµÑвÑм, он бÑÐ´ÐµÑ Ð¶Ð´Ð°ÑÑ Ð²ÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ long.js.
ÐÑо важно в ÑÐµÑ ÑлÑÑаÑÑ , когда нам ÑнаÑала нÑжно загÑÑзиÑÑ JavaScript-библиоÑекÑ, а заÑем ÑкÑипÑ, коÑоÑÑй Ð¾Ñ Ð½ÐµÑ Ð·Ð°Ð²Ð¸ÑиÑ.
defer пÑедназнаÑен ÑолÑко Ð´Ð»Ñ Ð²Ð½ÐµÑниÑ
ÑкÑипÑовÐÑÑибÑÑ defer бÑÐ´ÐµÑ Ð¿ÑоигноÑиÑован, еÑли в Ñеге <script> Ð½ÐµÑ src.
async
ÐÑÑибÑÑ async ознаÑаеÑ, ÑÑо ÑкÑÐ¸Ð¿Ñ Ð°Ð±ÑолÑÑно незавиÑим:
- СÑÑаниÑа не ждÑÑ Ð°ÑÐ¸Ð½Ñ ÑоннÑÑ ÑкÑипÑов, ÑодеÑжимое обÑабаÑÑваеÑÑÑ Ð¸ оÑобÑажаеÑÑÑ.
- СобÑÑие
DOMContentLoadedи аÑÐ¸Ð½Ñ ÑоннÑе ÑкÑипÑÑ Ð½Ðµ ждÑÑ Ð´ÑÑг дÑÑга:DOMContentLoadedÐ¼Ð¾Ð¶ÐµÑ Ð¿ÑоизойÑи как до аÑÐ¸Ð½Ñ Ñонного ÑкÑипÑа (еÑли аÑÐ¸Ð½Ñ ÑоннÑй ÑкÑÐ¸Ð¿Ñ Ð·Ð°Ð²ÐµÑÑÐ¸Ñ Ð·Ð°Ð³ÑÑÐ·ÐºÑ Ð¿Ð¾Ñле Ñого, как ÑÑÑаниÑа бÑÐ´ÐµÑ Ð³Ð¾Ñова),- â¦Ñак и поÑле аÑÐ¸Ð½Ñ Ñонного ÑкÑипÑа (еÑли он коÑоÑкий или Ñже ÑодеÑжиÑÑÑ Ð² HTTP-кеÑе)
- ÐÑÑалÑнÑе ÑкÑипÑÑ Ð½Ðµ ждÑÑ
async, и ÑкÑипÑÑ casyncне ждÑÑ Ð´ÑÑгие ÑкÑипÑÑ.
Так ÑÑо еÑли Ñ Ð½Ð°Ñ ÐµÑÑÑ Ð½ÐµÑколÑко ÑкÑипÑов Ñ async, они могÑÑ Ð²ÑполнÑÑÑÑÑ Ð² лÑбом поÑÑдке. То, ÑÑо пеÑвое загÑÑзиÑÑÑ â запÑÑÑиÑÑÑ Ð² пеÑвÑÑ Ð¾ÑеÑедÑ:
<p>...ÑодеÑжимое пеÑед ÑкÑипÑами...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM гоÑов!"));
</script>
<script async src="https://javascript.info/article/script-async-defer/long.js"></script>
<script async src="https://javascript.info/article/script-async-defer/small.js"></script>
<p>...ÑодеÑжимое поÑле ÑкÑипÑов...</p>
- СодеÑжимое ÑÑÑаниÑÑ Ð¾ÑобÑажаеÑÑÑ ÑÑÐ°Ð·Ñ Ð¶Ðµ :
asyncего не блокиÑÑеÑ. DOMContentLoadedÐ¼Ð¾Ð¶ÐµÑ Ð¿ÑоизойÑи как до, Ñак и поÑлеasync, Ð½Ð¸ÐºÐ°ÐºÐ¸Ñ Ð³Ð°ÑанÑий неÑ.- ÐÑинÑ
ÑоннÑе ÑкÑипÑÑ Ð½Ðµ ждÑÑ Ð´ÑÑг дÑÑга. ÐенÑÑий ÑкÑипÑ
small.jsидÑÑ Ð²ÑоÑÑм, но ÑкоÑее вÑего загÑÑзиÑÑÑ ÑанÑÑеlong.js, поÑÑÐ¾Ð¼Ñ Ð¸ запÑÑÑиÑÑÑ Ð¿ÐµÑвÑм. То еÑÑÑ, ÑкÑипÑÑ Ð²ÑполнÑÑÑÑÑ Ð² поÑÑдке загÑÑзки.
ÐÑÐ¸Ð½Ñ ÑоннÑе ÑкÑипÑÑ Ð¾ÑÐµÐ½Ñ Ð¿Ð¾Ð»ÐµÐ·Ð½Ñ Ð´Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑаниÑÑ ÑÑоÑÐ¾Ð½Ð½Ð¸Ñ ÑкÑипÑов: ÑÑÑÑÑиков, ÑÐµÐºÐ»Ð°Ð¼Ñ Ð¸ Ñ.д. Ðни не завиÑÑÑ Ð¾Ñ Ð½Ð°ÑÐ¸Ñ ÑкÑипÑов, и Ð¼Ñ Ñоже не Ð´Ð¾Ð»Ð¶Ð½Ñ Ð¶Ð´Ð°ÑÑ Ð¸Ñ :
<!-- ТипиÑное подклÑÑение ÑкÑипÑа Google Analytics -->
<script async src="https://google-analytics.com/analytics.js"></script>
async пÑедназнаÑен ÑолÑко Ð´Ð»Ñ Ð²Ð½ÐµÑниÑ
ÑкÑипÑовÐак и в ÑлÑÑае Ñ defer, аÑÑибÑÑ async бÑÐ´ÐµÑ Ð¿ÑоигноÑиÑован, еÑли в Ñеге <script> Ð½ÐµÑ src.
ÐинамиÑеÑки загÑÑжаемÑе ÑкÑипÑÑ
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ Ñакже добавиÑÑ ÑкÑÐ¸Ð¿Ñ Ð¸ динамиÑеÑки, Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ JavaScript:
let script = document.createElement('script');
script.src = "/article/script-async-defer/long.js";
document.body.append(script); // (*)
СкÑÐ¸Ð¿Ñ Ð½Ð°ÑнÑÑ Ð·Ð°Ð³ÑÑжаÑÑÑÑ, как ÑолÑко он бÑÐ´ÐµÑ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½ в докÑÐ¼ÐµÐ½Ñ (*).
ÐинамиÑеÑки загÑÑжаемÑе ÑкÑипÑÑ Ð¿Ð¾ ÑмолÑÐ°Ð½Ð¸Ñ Ð²ÐµÐ´ÑÑ ÑÐµÐ±Ñ ÐºÐ°Ðº «async».
То еÑÑÑ:
- Ðни никого не ждÑÑ, и Ð¸Ñ Ð½Ð¸ÐºÑо не ждÑÑ.
- СкÑипÑ, коÑоÑÑй загÑÑжаеÑÑÑ Ð¿ÐµÑвÑм â запÑÑкаеÑÑÑ Ð¿ÐµÑвÑм (в поÑÑдке загÑÑзки).
ÐÑ Ð¼Ð¾Ð¶ÐµÐ¼ измениÑÑ Ð¾ÑноÑиÑелÑнÑй поÑÑдок ÑкÑипÑов Ñ Â«Ð¿ÐµÑвÑй загÑÑзилÑÑ â пеÑвÑй вÑполнилÑÑ» на поÑÑдок, в коÑоÑом они идÑÑ Ð² докÑменÑе (как в обÑÑнÑÑ
ÑкÑипÑаÑ
) Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ñвной ÑÑÑановки ÑвойÑÑва async в false:
let script = document.createElement('script');
script.src = "/article/script-async-defer/long.js";
script.async = false;
document.body.append(script);
ÐапÑимеÑ, здеÑÑ Ð¼Ñ Ð´Ð¾Ð±Ð°Ð²Ð»Ñем два ÑкÑипÑа. Ðез script.async=false они запÑÑкалиÑÑ Ð±Ñ Ð² поÑÑдке загÑÑзки (small.js ÑкоÑее вÑего запÑÑÑилÑÑ Ð±Ñ ÑанÑÑе). Ðо Ñ ÑÑим Ñлагом поÑÑдок бÑÐ´ÐµÑ ÐºÐ°Ðº в докÑменÑе:
function loadScript(src) {
let script = document.createElement('script');
script.src = src;
script.async = false;
document.body.append(script);
}
// long.js запÑÑкаеÑÑÑ Ð¿ÐµÑвÑм, Ñак как async=false
loadScript("/article/script-async-defer/long.js");
loadScript("/article/script-async-defer/small.js");
ÐÑого
У async и defer еÑÑÑ ÐºÐ¾Ðµ-ÑÑо обÑее: они не блокиÑÑÑÑ Ð¾ÑÑиÑÐ¾Ð²ÐºÑ ÑÑÑаниÑÑ. Так ÑÑо полÑзоваÑÐµÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑоÑмоÑÑеÑÑ ÑодеÑжимое ÑÑÑаниÑÑ Ð¸ ознакомиÑÑÑÑ Ñ Ð½ÐµÐ¹ ÑÑÐ°Ð·Ñ Ð¶Ðµ.
Ðо еÑÑÑ Ð¸ знаÑимÑе ÑазлиÑиÑ:
| ÐоÑÑдок | DOMContentLoaded |
|
|---|---|---|
async |
ÐоÑÑдок загÑÑзки (кÑо загÑÑзиÑÑÑ Ð¿ÐµÑвÑм, ÑÐ¾Ñ Ð¸ ÑÑабоÑаеÑ). | Ðе Ð¸Ð¼ÐµÐµÑ Ð·Ð½Ð°ÑениÑ. ÐÐ¾Ð¶ÐµÑ Ð·Ð°Ð³ÑÑзиÑÑÑÑ Ð¸ вÑполниÑÑÑÑ Ð´Ð¾ Ñого, как ÑÑÑаниÑа полноÑÑÑÑ Ð·Ð°Ð³ÑÑзиÑÑÑ. Такое ÑлÑÑаеÑÑÑ, еÑли ÑкÑипÑÑ Ð¼Ð°Ð»ÐµÐ½Ñкие или Ñ ÑанÑÑÑÑ Ð² кеÑе, а докÑÐ¼ÐµÐ½Ñ Ð´Ð¾ÑÑаÑоÑно болÑÑой. |
defer |
ÐоÑÑдок докÑменÑа (как ÑаÑÐ¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ñ Ð² докÑменÑе). | ÐÑполнÑеÑÑÑ Ð¿Ð¾Ñле Ñого, как докÑÐ¼ÐµÐ½Ñ Ð·Ð°Ð³ÑÑжен и обÑабоÑан (ждÑÑ), непоÑÑедÑÑвенно пеÑед DOMContentLoaded. |
ÐожалÑйÑÑа, помниÑе, ÑÑо когда Ð²Ñ Ð¸ÑполÑзÑеÑе defer, ÑÑÑаниÑа видна до Ñого, как ÑкÑÐ¸Ð¿Ñ Ð·Ð°Ð³ÑÑзиÑÑÑ.
ÐолÑзоваÑÐµÐ»Ñ Ð¼Ð¾Ð¶ÐµÑ Ð·Ð½Ð°ÐºÐ¾Ð¼Ð¸ÑÑÑÑ Ñ ÑодеÑжимÑм ÑÑÑаниÑÑ, ÑиÑаÑÑ ÐµÑ, но гÑаÑиÑеÑкие компоненÑÑ Ð¿Ð¾ÐºÐ° оÑклÑÑенÑ.
ÐоÑÑÐ¾Ð¼Ñ Ð¾Ð±ÑзаÑелÑно должна бÑÑÑ Ð¸Ð½Ð´Ð¸ÐºÐ°ÑÐ¸Ñ Ð·Ð°Ð³ÑÑзки, неÑабоÑие кнопки â оÑклÑÑÐµÐ½Ñ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ CSS или дÑÑгим обÑазом. ЧÑÐ¾Ð±Ñ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ñвно видел, ÑÑо Ñже гоÑово, а ÑÑо пока неÑ.
Ðа пÑакÑике defer иÑполÑзÑеÑÑÑ Ð´Ð»Ñ ÑкÑипÑов, коÑоÑÑм ÑÑебÑеÑÑÑ Ð´Ð¾ÑÑÑп ко вÑÐµÐ¼Ñ DOM и/или важен иÑ
оÑноÑиÑелÑнÑй поÑÑдок вÑполнениÑ.
Ð async Ñ
оÑÐ¾Ñ Ð´Ð»Ñ Ð½ÐµÐ·Ð°Ð²Ð¸ÑимÑÑ
ÑкÑипÑов, напÑÐ¸Ð¼ÐµÑ ÑÑÑÑÑиков и ÑекламÑ, оÑноÑиÑелÑнÑй поÑÑдок вÑÐ¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾ÑоÑÑÑ
не игÑÐ°ÐµÑ Ñоли.
ÐомменÑаÑии
<code>, Ð´Ð»Ñ Ð½ÐµÑколÑÐºÐ¸Ñ ÑÑÑок кода — Ñег<pre>, еÑли болÑÑе 10 ÑÑÑок — ÑÑÑÐ»ÐºÑ Ð½Ð° пеÑоÑниÑÑ (plnkr, JSBin, codepenâ¦)