>웹 프론트엔드 >JS 튜토리얼 >브라우저 환경에서 JavaScript 스크립트 로딩 및 실행 분석: 지연 및 비동기 특성_javascript 기술

브라우저 환경에서 JavaScript 스크립트 로딩 및 실행 분석: 지연 및 비동기 특성_javascript 기술

WBOY
WBOY원래의
2016-05-16 15:20:021651검색

defer 및 async 기능은 많은 JavaScript 개발자에게 "익숙하지만 익숙하지 않은" 두 가지 기능이라고 생각됩니다. 문자 그대로 보면 이 두 기능이 "지연 스크립트"입니다. 및 "비동기 스크립트" 효과입니다. 그러나 연기를 예로 들면 개발자는 연기 기능이 있는 스크립트의 실행이 언제 지연되는지, 내부 스크립트와 외부 스크립트가 연기 후 스크립트를 지원할 수 있는지 여부와 같은 일부 세부 사항에 익숙하지 않을 수 있습니다. 지연 실행 외에 특별한 기능은 무엇입니까? 이 기사는 개발자가 이 두 기능을 더 잘 익히는 데 도움이 되기를 바라며 기존 기사와 MDN 문서의 두 기능에 대한 설명을 결합하여 지연 및 비동기에 대한 보다 포괄적인 연구와 요약을 수행합니다.

1 소개

"브라우저 환경에서 JavaScript 스크립트 로드 및 실행 분석: 코드 실행 순서"에서 JavaScript 코드를 실행하면 페이지의 구문 분석 및 렌더링과 다른 리소스의 다운로드가 차단된다고 언급했습니다. 물론 JavaScript는 단일 스레드 언어이기 때문에 일반적인 상황에서는 페이지의 JavaScript 코드가 위에서 아래로 순서대로만 실행될 수 있습니다. 브라우저 환경에서의 스크립트 로딩 및 실행 "실행 순서 "에서 분석한 것처럼 document.write를 통해 스크립트를 입력하거나 동적 스크립트 기술을 통해 스크립트를 도입하는 경우와 같은 경우에는 JavaScript 코드의 실행 순서가 반드시 위에서 아래로 엄격한 순서를 따를 필요는 없습니다. 지연 및 비동기도 우리가 "비정상적인 상황"이라고 부르는 것입니다.

실제 개발에서 우리가 일반적으로 가장 우려하는 차단과 사용자 경험에 가장 큰 영향을 미치는 차단은 다음과 같은 측면이 있어야 합니다.


[1] 페이지 분석 및 렌더링 차단


[2] 우리가 작성한 페이지 초기화 스크립트(일반적으로 DOMContentLoaded 이벤트를 수신하기 위해 바인딩된 스크립트) 스크립트의 이 부분은 사용자 상호 작용과 가장 관련된 코드를 작성하기 때문에 먼저 실행하려는 스크립트입니다. 여기 )


[3] 페이지 내 외부 리소스(사진 등) 다운로드 차단


시간이 많이 걸리는 스크립트 작업이 있고 이 스크립트가 위에서 언급한 세 곳을 차단하는 경우 이 웹페이지의 성능이나 사용자 경험이 매우 저하됩니다.


defer와 async의 두 가지 기능의 원래 의도는 차단이 페이지 경험에 미치는 영향을 해결하거나 완화하는 것입니다. 아래에서 이 두 가지 기능을 주로 다음과 같은 측면에서 분석하겠습니다.


[1]지연 또는 비동기 스크립트의 실행 시간은 언제인가요? 페이지 차단은 어떻습니까?


[2] 내부 및 외부 스크립트 모두 지연 또는 비동기 구현이 가능합니까?


[3] 브라우저는 이 두 가지 기능을 얼마나 잘 지원합니까? 관련된 버그가 있나요?


[4] 이 두 가지 기능을 사용하는 스크립트를 사용할 때 또 주의해야 할 사항이 있나요?


2가지 연기 기능

2.1 defer 스크립트 실행 시기에 대해

defer 기능은 HTML4 사양에 정의된 확장 기능입니다. 처음에는 IE4 및 Firefox3.5에서만 지원되었으며 나중에 Chrome과 같은 브라우저에서도 defer="defer"를 사용하여 지원을 추가했습니다. defer는 지연을 의미하며, 이는 스크립트 실행이 지연된다는 의미입니다. 일반적인 상황에서는 우리가 소개하는 스크립트가 즉시 다운로드되어 실행됩니다. 그러나 defer 기능을 사용하면 다운로드 후 스크립트가 즉시 실행되지 않고 페이지가 구문 분석된 후에 실행됩니다. HTML4 표준의 defer 설명을 살펴보겠습니다.


defer: 설정되면 이 부울 속성은 스크립트가 문서 콘텐츠를 생성하지 않을 것이라는 힌트를 사용자 에이전트에 제공하므로(예: javascript에서는 "document.write"가 없음) 사용자 에이전트가 구문 분석을 계속할 수 있습니다. 렌더링합니다.


즉, defer가 설정되면 이 스크립트는 문서 콘텐츠를 생성하지 않을 것임을 사용자 에이전트에 알리므로 사용자 에이전트는 계속해서 구문 분석하고 렌더링할 수 있습니다. MDN의 defer에 대한 주요 설명을 다시 살펴보겠습니다:


defer: async 속성은 없지만 defer 속성이 있는 경우 페이지 구문 분석이 완료되면 스크립트가 실행됩니다.


표준의 정의를 통해 defer 스크립트가 페이지 구문 분석을 차단하지 않고 페이지 구문 분석이 완료될 때까지 기다렸다가 실행한다는 점을 분명히 할 수 있습니다. 그러나 여전히 시간이 많이 걸리는 defer가 있을 수 있습니다. 외부 리소스 다운로드를 차단하면 DOMContentLoaded 이벤트가 차단되나요? 실제로 defer 스크립트는 DOMContentLoaded 이벤트 이전에 계속 실행되므로 DOMContentLoaded에서 스크립트를 계속 차단합니다. 다음 그림을 사용하면 defer 스크립트의 실행 타이밍을 이해하는 데 도움이 됩니다.



표준의 정의에 따르면 내부 스크립트는 연기를 지원하지 않지만, IE9 이하 브라우저에서는 내부 스크립트에 대한 연기 지원을 제공합니다.


2.2 브라우저 지원 연기

연기 기능에 대한 브라우저 지원을 살펴보겠습니다.


IE9 이하 브라우저에는 버그가 있는데, 이에 대해서는 추후 DEMO에서 자세히 설명하겠습니다.

2.3 DEMO: 연기 기능의 기능 검증

연기 속성의 기능을 확인하기 위해 "스크립트 연기 속성"에서 Olivier Rochard가 사용한 방법을 모방합니다.

먼저 6개의 외부 스크립트를 준비했습니다.

1.js:

test = "나는 외부 스크립트 n입니다."

2.js

test = "나는 신체 외부 스크립트 n입니다"

3.js

test = "저는 하단 외부 스크립트 n입니다"

defer1.js

test = "나는 헤드 외부 지연 스크립트 n입니다"

defer2.js

test = "나는 신체 외부 지연 스크립트 n입니다"

defer3.js

test = "저는 하단 외부 지연 스크립트 n입니다"

HTML의 코드는 다음과 같습니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>defer attribute test</title>
<script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
<script type="text/javascript">var test = "";</script>
<script src="defer1.js" type="text/javascript" defer="defer"></script>
<script src="1.js" type="text/javascript"></script>
<script defer="defer">
test += "我是head延迟内部脚本\n";
</script>
<script>
test += "我是head内部脚本\n";
</script>
</head>
<body>
<button id="test">点击一下</button>
<script src="defer2.js" type="text/javascript" defer="defer"></script>
<script src="2.js" type="text/javascript"></script>
</body>
<script src="defer3.js" type="text/javascript" defer="defer"></script>
<script src="3.js" type="text/javascript"></script>
<script>
$(function(){
test += "我是DOMContentLoaded里面的脚本
";
})
window.onload = function(){
test += "我是window.onload里面的脚本
";
var button = document.getElementById("test");
button.onclick = function(){
alert(test);
}
}
</script>
</html> 

코드에서는 DOMContentLoaded 이벤트 구현을 용이하게 하기 위해 jQuery를 도입했습니다(나중에 호환되는 DOMContentLoaded를 직접 구현하는 방법을 소개할 예정입니다). 그런 다음 헤드, 바디 내부 및 외부에 지연 스크립트를 도입했습니다. 스크립트의 본문과 일반 스크립트를 살펴보고, 전역 문자열을 통해 각 코드의 실행 상태를 기록합니다. 각 브라우저의 실행 결과를 살펴보겠습니다.

IE7 IE9 IE10 크롬 파이어폭스

저는 외부 스크립트 책임자입니다

IE7 IE9 IE10 CHROME firefox

我是head外部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是head延迟内部脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是head延迟内部脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head延迟内部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head延迟内部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

<br />我是head外部脚本
<span style="color: rgb(255,0,0)">我是head延迟内部脚本</span>
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
<span style="color: rgb(255,0,0)">我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本</span>
저는 내부 스크립트 책임자입니다 나는 신체 외부 스크립트입니다 저는 하단 외부 스크립트입니다 저는 외부 지연 스크립트를 맡고 있습니다 저는 헤드 딜레이 내부 스크립트입니다 나는 신체 외부 지연 스크립트 저는 하단 외부 지연 스크립트입니다 나는 DOMContentLoaded의 스크립트입니다 저는 window.onload의 스크립트입니다
저는 외부 스크립트 책임자입니다 저는 내부 스크립트 책임자입니다 나는 신체 외부 스크립트입니다 저는 하단 외부 스크립트입니다 저는 외부 지연 스크립트를 맡고 있습니다 저는 헤드 딜레이 내부 스크립트입니다 나는 신체 외부 지연 스크립트 저는 하단 외부 지연 스크립트입니다 나는 DOMContentLoaded의 스크립트입니다 저는 window.onload의 스크립트입니다 저는 외부 스크립트 책임자입니다 내부 스크립트가 너무 지연되었습니다 저는 내부 스크립트 책임자입니다 나는 신체 외부 스크립트입니다 저는 하단 외부 스크립트입니다 저는 외부 지연 스크립트를 맡고 있습니다 나는 신체 외부 지연 스크립트 저는 하단 외부 지연 스크립트입니다 나는 DOMContentLoaded의 스크립트입니다 저는 window.onload의 스크립트입니다 저는 외부 스크립트 책임자입니다 내부 스크립트가 너무 지연되었습니다 저는 내부 스크립트 책임자입니다 나는 신체 외부 스크립트입니다 저는 하단 외부 스크립트입니다 저는 외부 지연 스크립트를 맡고 있습니다 나는 신체 외부 지연 스크립트 저는 하단 외부 지연 스크립트입니다 나는 DOMContentLoaded의 스크립트입니다 저는 window.onload의 스크립트입니다

从输出的结果中我们可以确定,只有IE9及以下浏览器支持内部延迟脚本,并且defer后的脚本都会在DOMContentLoaded事件之前触发,因此也是会堵塞DOMContentLoaded事件的。

2.4 DEMO:IE0f630a08ba48c70580451c5807d38ff4我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
document.body.innerHTML += "7a6bc4f2a125532aca32e87dac970576我是后来加入的16b28748ea4df4d9c2150843fecfba68";
alert("我是第1个脚本");

2.js

alert("我是第2个脚本");

修改HMTL中的代码为:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>defer bug in IE=9 test</title>
<script src="1.js" type="text/javascript" defer="defer"></script>
<script src="2.js" type="text/javascript" defer="defer"></script>
</head>
<body>
</body>
</html>

正常情况下,浏览器中弹出框的顺序肯定是:我是第1个脚本-》我是第2个脚本,然而在IE77f5db5c498cd8790c183e49397570fd 요소가 defer 및 async 속성을 모두 정의하는 경우 비동기로 처리됩니다(참고: 비동기를 지원하지 않는 브라우저는 비동기 속성을 직접 무시합니다)

[2] 3f1c4e4b6b16bbbd69b2ee476dc4f83a 요소가 defer만 정의하는 경우 지연된 스크립트로 처리됩니다.

[3] 3f1c4e4b6b16bbbd69b2ee476dc4f83a 요소가 defer 또는 async를 정의하지 않으면 정상적으로 처리됩니다. 즉, 스크립트가 즉시 로드되고 실행됩니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.