머리말
나는 모든 사람들이 JavaScript 스크립트로드와 관련하여 많은 문제를 겪었다고 생각합니다. 주로 여러 지점에서 -
1> 파일로드, 파일 종속성 및 동기 스크립트 및 비동기 스크립트로 인한 실행 순서 문제
2> 동기 스크립트 및 비동기 스크립트로 인한 성능 최적화 문제
스크립트 로딩의 모든 측면에 대한 깊은 이해는 실제 문제를 해결하는 데 도움이 될뿐만 아니라 성능 최적화를 파악하고 실행하는 데 도움이됩니다.
먼저 스크립트 태그 코드를보십시오.
코드 사본은 다음과 같습니다.
<script src = "js/myapp.js"> </script>
<head>에 배치되면 모든 페이지 렌더링 작업을 차단하여 스크립트가로드되고 실행될 때까지 사용자가 "흰색 죽음의 화면"상태를 유지하게됩니다. <body> 끝의 스크립트는 사용자가 활력없이 정적 페이지를 볼 수있게합니다. 클라이언트 렌더링에는 비효율적 인 컨트롤과 빈 상자가 흩어져 있어야합니다. 테스트 케이스를 가져 가십시오 -
코드 사본은 다음과 같습니다.
<! doctype html>
<html>
<head lang = "en">
<meta charset = "utf-8">
<title> 비동기로드 스크립트 </title>
<script src = "js/test.js"> </script>
</head>
<body>
<div> 나는 내용입니다 </div>
<img src = "img/test.jpg">
</body>
</html>
그중에서도 test.js의 내용 -
코드 사본은 다음과 같습니다.
경고 ( '나는 헤드의 스크립트 코드입니다. 여기에서 JS를 실행 한 후 신체 내용 렌더링이 시작됩니다!');
우리는 경고가 일시 중지 지점이라는 것을 알 수 있으며, 현재로서는 페이지가 비어 있습니다. 그러나 현재 전체 페이지가로드되었습니다. 본문에 특정 SRC 속성에 대한 태그 (위의 IMG 태그 등)에 대한 태그가 포함 된 경우 브라우저는 현재 관련 컨텐츠를로드하기 시작했습니다. 요컨대, JS 엔진과 렌더링 엔진의 작동시기는 상호 배타적이라는 점에 유의해야합니다 (일부 책은 UI 스레드라고합니다).
따라서 페이지를 더 좋아 보이게하는 스크립트가 필요하며 나중에로드 할 수있는 스크립트는 나중에로드됩니다.
1. 스크립트 실행 지연
이제 <body> 태그의 끝에 스크립트를 배치하는 것이 점점 더 인기를 얻고 있습니다. 이런 식으로, 한편으로, 사용자는 페이지를 더 빨리 볼 수 있으며 다른 한편으로는 스크립트가로드 된 DOM 요소를 직접 작동 할 수 있습니다. 이 "이동"은 대부분의 스크립트에서 큰 개선입니다. 페이지 모델은 다음과 같습니다.
코드 사본은 다음과 같습니다.
<! doctype html>
<html>
<head lang = "en">
<!-메타 데이터 및 스크립트 시트는 여기로 이동->
<script src = "headscript.js"> </script>
</head>
<body>
<!-콘텐츠가 여기에 간다->
<script src = "bodyscript.js"> </script>
</body>
</html>
이렇게하면 페이지의 렌더링 시간이 크게 높아지지만,이를 통해 사용자는 BodyScript가로드되기 전에 페이지와 상호 작용할 수있는 기회를 제공 할 수 있습니다. 전체 문서를로드하기 전에 브라우저가 스크립트를로드 할 수없는 이유는 느린 연결을 통해 전송되는 큰 문서에 대한 큰 병목 현상입니다.
이상적으로, 스크립트의로드는 문서의로드와 동시에 수행해야하며 DOM의 렌더링에는 영향을 미치지 않습니다. 이렇게하면 문서가 준비되면 해당 스크립트가 <cript> 태그 순서대로로드되었으므로 스크립트를 실행할 수 있습니다.
우리는 연기를 사용 하여이 요구 사항을 달성 할 수 있습니다.
코드 사본은 다음과 같습니다.
<script src = "deferredscript.js"> </script>
DEFER 속성을 추가하는 것은 브라우저에 알려주는 것과 같습니다. 즉시이 스크립트로드를 시작하십시오. 그러나 문서가 준비 될 때까지 기다려주십시오.
이런 식으로, 지연 스크립트를 헤드 태그에 넣으면 스크립트를 본체 태그에 배치 할 때의 모든 이점을 가져 오며 큰 문서의 로딩 속도를 크게 향상시킬 수 있습니다. 이 시점의 페이지 모드는 -
코드 사본은 다음과 같습니다.
<! doctype html>
<html>
<head lang = "en">
<!-메타 데이터 및 스크립트 시트는 여기로 이동->
<script src = "headscript.js"> </script>
<script src = "deferredscript.js"defer> </script>
</head>
<body>
<!-콘텐츠가 여기에 간다->
</body>
</html>
그러나 모든 브라우저가 연기를 지원하는 것은 아닙니다 (일부 최신 브라우저의 경우 연기가 선언되면 내부 스크립트는 문서 및 DOM 렌더링 작업을 수행하지 않습니다. IE4+ 지원 연기 속성 모두). 즉, 문서가로드 된 후 지연 스크립트가 실행될 수 있으려면 jQuery의 $ (Document). Ready와 같은 구조로 모든 지연 스크립트의 코드를 캡슐화해야합니다. 방문자의 거의 97%가 병렬 로딩의 이점을 누릴 수있는 반면, 방문객의 3%는 여전히 완전한 기능을 갖춘 JavaScript를 사용할 수 있기 때문에 그만한 가치가 있습니다.
2. 스크립트의 완전한 병렬화
스크립트를 한 단계 더 빨리로드하고 실행하도록하십시오. 연기 스크립트가 차례로 실행될 때까지 기다리고 싶지 않습니다 (DEFER는 문서가 조용히 문서로드되기를 기다리는 순서 대기열 시나리오를 상기시켜줍니다). 가능한 빨리이 스크립트를로드하고 실행하고 싶습니다. 여기서 우리는 html5의 비동기 속성을 생각하지만 그것이 혼란스러운 무정부 상태라는 점에 유의하십시오.
예를 들어, 우리는 완전히 관련이없는 두 개의 타사 스크립트를로드하고 페이지는 그들없이 잘 실행되며 누가 먼저 달리고 누가 나중에 달리는 지 신경 쓰지 않습니다. 따라서이 타사 스크립트에서 비동기 속성을 사용하는 것은 페니를 쓰지 않고 달리기 속도를 향상시키는 것과 같습니다.
비동기 속성은 HTML5에 새로 추가됩니다. 이 기능은 연기와 유사합니다. 즉, 스크립트를 다운로드하는 동안 DOM 렌더링을 허용합니다. 그러나 다운로드 후 가능한 빨리 실행됩니다 (즉, JS 엔진이 유휴 상태이며 즉시 실행됨). 스크립트가 순서대로 실행되었다는 보장은 없습니다. Onload 이벤트 전에 완료됩니다.
Firefox 3.6, Opera 10.5, IE 9 및 최신 크롬 및 사파리는 모두 비동기 속성을 지원합니다. Async 및 DEFER는 동시에 사용될 수 있으므로 IE 4 이후의 모든 IE가 비동기 부하를 지원할 수 있지만 Async가 연체 연기가 연기되도록주의하십시오.
이 시점의 페이지 모델은 다음과 같습니다.
코드 사본은 다음과 같습니다.
<! doctype html>
<html>
<head lang = "en">
<!-메타 데이터 및 스크립트 시트는 여기로 이동->
<script src = "headscript.js"> </script>
<script src = "deferredscript.js"defer> </script>
</head>
<body>
<!-콘텐츠가 여기에 간다->
<script src = "asyncscript1.js"async defer> </script>
<script src = "asyncscript2.js"async defer> </script>
</body>
</html>
여기에서 실행 순서에주의하십시오 - 각 스크립트 파일이로드 된 다음 headscript.js가 실행 된 다음 DeferedScript.js가 백그라운드에로드되어 Dom 렌더링됩니다. 그런 다음 DefferedScript.js와 두 개의 비동기 스크립트가 Dom 렌더링 끝에 실행됩니다. 비동기 속성을 지원하는 브라우저의 경우이 두 스크립트가 순서 부족합니다.
3. 프로그래밍 가능한 스크립트로드
위의 두 스크립트 속성의 기능은 매우 매력적이지만 호환성 문제로 인해 널리 사용되지 않습니다. 따라서 스크립트를 사용하여 다른 스크립트를 더 많이로드합니다. 예를 들어, 특정 조건을 충족하는 사용자를 위해 스크립트 만로드하려고합니다. 이는 종종 언급 된 "게으른로드"입니다.
브라우저 API 레벨에는 서버 스크립트를 크롤링하고 실행하는 두 가지 합리적인 방법이 있습니다.
1> ajax 요청을 생성하고 평가 기능을 사용하여 응답을 처리합니다.
2> <Script> 태그를 DOM에 삽입하십시오
브라우저가 HTTP 요청을 생성하는 것에 대해 걱정할 것이기 때문에 후자의 방법은 더 좋습니다. 또한 Eval에는 몇 가지 실제 문제가 있습니다. 누출 범위, 디버깅은 지저분하며 성능을 줄일 수 있습니다. 따라서 feature.js라는 스크립트를로드하려면 다음과 같은 코드를 사용해야합니다.
코드 사본은 다음과 같습니다.
var head = document.getElementsByTagName ( 'head') [0];
var script = document.createElement ( 'script');
script.src = 'feaction.js';
Head.appendChild (스크립트);
물론, 우리는 콜백 청취를 처리해야하며 HTML5 사양은 콜백을 바인딩 할 수있는 Onload 속성을 정의합니다.
코드 사본은 다음과 같습니다.
script.onload = function () {
console.log ( '스크립트로드 ...');
}
그러나 IE8 및 이전 버전은 OnLoad를 지원하지 않으며 OnReadyStateChange를 지원합니다. 또한, 오류를 다루는 것이 여전히 많은 이상한 것들이 있습니다. 여기서는 Labjs, Yepnope, Equirejs 등과 같은 인기있는 학교 기반 적재 라이브러리를 참조 할 수 있습니다.
다음과 같이 간단한 loadjs 파일을 직접 캡슐화합니다.
코드 사본은 다음과 같습니다.
var loadjs = function (url, 콜백) {
var head = document.getElementsByTagName ( 'head') [0];
var script = document.createElement ( 'script');
script.src = url;
script.type = "text/javaScript";
Head.appendChild (스크립트);
// 스크립트 태그, IE에 따라 OnreadyStateChange 이벤트가 있으며 W3C 표준에 따라 Onload 이벤트가 있습니다.
// IE9+는 또한 W3C 표준의 Onload도 지원합니다
var ua = navigator.useragent,
ua_version;
// IE6/7/8
if (/msie ([^;]+)/. test (ua)) {
ua_version = parsefloat (regexp [ "$ 1"], 10);
if (ua_version <= 8) {
script.onreadyStateChange = function () {
if (this.readystate == "loaded") {
콜백 ();
}
}
} 또 다른 {
script.onload = function () {
콜백 ();
};
}
} 또 다른 {
script.onload = function () {
콜백 ();
};
}
};
Document.Write에서 스크립트의 비동기로드에 대해서는 이야기하지 않습니다. 브라우저 차이가 정말 압도적이기 때문에 이제는이 작업을 수행하는 사람이 거의 없습니다.
이미지 개체를 사용하여 JS 파일을 예압하여 비동기 적으로 JS 코드는 실행되지 않습니다.
마지막으로 requirejs의 비동기로드 스크립트에 대해 이야기 해 봅시다.
요구 사항은 대상 스크립트가 순차적으로 실행되도록 보장하지는 않지만 실행 순서가 각각의 종속성 요구 사항을 충족 할 수 있도록 보장합니다. 따라서 모든 스크립트가 최대한 빨리 병렬로로드되도록하고 종속성 토폴로지에 따라 순서대로 실행하십시오.
4. 요약
자, 이에 관해서는 비동기로드 스크립트의 진술이 끝났습니다. 여기서 최적화 순서에 대해 다시 이야기하겠습니다.
1> 전통적인 방식으로 스크립트 태그를 사용하여 HTML 문서에 직접 포함시킵니다. 다음은 두 가지 상황입니다.
a> 헤드 태그에 포함 - 그렇게하면 문서 컨텐츠에서 다른 정적 리소스 파일의 병렬로드에 영향을 미치지 않도록주의하십시오. 문서 내용의 렌더링에 영향을 미칩니다. 즉, 현재 DOM 렌더링이 차단되고 흰색 화면이 제시됩니다.
B> 신체 태그의 바닥에 포함 - 흰색 스크린 현상을 피하기 위해 DOM을 렌더링 한 다음 스크립트를 실행하는 데 우선 순위를 부여하지만 문제가 다시 발생합니다. 첫 번째 질문에 대해 먼저 이야기 해 봅시다. DOM 문서의 내용이 비교적 크면 상호 작용 이벤트 바인딩이 지연되고 경험이 조금 더 나빠질 것입니다. 물론 필요에 따라 중요한 스크립트를 먼저 실행해야합니다. 두 번째 문제에 대해 이야기 해 봅시다. 스크립트 파일은 본문의 바닥까지 이므로이 스크립트의로드는 헤드의 스크립트에 비해 지연됩니다. 따라서 신체의 바닥은 최적화의 종말점이 아닙니다.
C> 추가 DEFER 속성 - 스크립트가 가능한 빨리 병렬로로드되기를 바랍니다.이 스크립트 배치를 헤드에 넣을 것입니다. 스크립트의로드는 문서의로드와 동시에 수행해야하며 DOM의 렌더링에는 영향을 미치지 않습니다. 이렇게하면 문서가 준비되면 스크립트를 실행할 수 있습니다. 따라서 연기 속성이 있습니다. 그러나 호환성에주의하십시오. DEFER 속성을 지원하지 않는 브라우저의 경우 jQuery와 같은 $ (문서)에 코드를 캡슐화해야합니다. 지연 속성이있는 모든 스크립트는 외관 순서에 따라 순서대로 실행되므로 엄격하게 동기화됩니다.
2> 이전 요점은 동기 실행 스크립트에 관한 것입니다 (이 스크립트의로드 프로세스는 평행하지만, 누가 요청을 먼저 트리거하고 누가 요청을 트리거 하는가)의 차이). 다음 최적화 지점은 "병렬 실행 스크립트"입니다. 물론, 우리는 어느 시점에서 하나의 JS 파일 만 실행된다는 것을 알고 있습니다. 여기서 "평행"은 JS 엔진이 유휴 상태 인 한 누가 먼저로드하는 사람이라면 즉시 실행됩니다. 여기서 최적화는 두 가지 유형으로 나뉩니다.
A> Async 속성 추가 - 위에서 언급 한 최적화 지점을 실제로 완료 할 수 있지만, 높은 제한 사항이 있습니다. 즉, 비 의존성 스크립트로드에만 해당됩니다. 가장 적합한 예는 여러 타사 스크립트를 소개하는 것입니다. 또한 Deffer 속성과의 조합은 실제로 큰 문제입니다. 물론, 그것은 또한 호환성 문제가 있습니다. 위의 세 가지 문제로 인해 드물게 적용되었습니다. 비동기를 사용하는 경우 종속성 문제에주의를 기울여야합니다.
b> 스크립트로드 스크립트 - 분명히, 우리는 이것을 사용하여 "스크립트의 병렬 실행"의 목적을 달성합니다. 동시에, 우리는 스크립트 종속성의 제어를 용이하게하므로 requirejs의 비동기로드에 지능형로드 관리를 사용합니다.
좋아, 그게 다야.
여기서는 비동기로드 스크립트와 관련된 내용에 대해 이야기하고 있습니다. 컨텐츠의 또 다른 부분이 있는데, 이는 스타일 파일 또는 기타 정적 리소스의 비동기로드입니다. 계속하려면 ......