스크립트 순서로드 및 실행


265

html 페이지에 JavaScript를 포함시키는 방법에는 여러 가지가 있습니다. 다음 옵션에 대해 알고 있습니다.

  • 인라인 코드 또는 외부 URI에서로드
  • <head> 또는 <body> 태그에 포함됨 [ 1 , 2 ]
  • 없음 defer또는 async속성이있는 경우 (외부 스크립트 만 해당)
  • 정적 소스에 포함되거나 다른 스크립트에 의해 동적으로 추가됨 (다른 구문 분석 상태에서 다른 방법으로)

하드 디스크, javascript : URIs 및 onEvent-attributes [ 3 ] 에서 브라우저 스크립트를 계산하지 않고 이미 JS를 실행하는 16 가지 대안이 있으며 무언가를 잊어 버린 것 같습니다.

나는 빠른 (병렬) 로딩에 관심이 없으며 실행 순서 (로드 순서 및 문서 순서 에 따라 다름)에 대해 더 궁금합니다 . 실제로 모든 경우를 다루는 좋은 (크로스 브라우저) 참조가 있습니까? 예를 들어 http://www.websiteoptimization.com/speed/tweak/defer/ 는 6 개만 처리하며 대부분 오래된 브라우저를 테스트합니다.

그렇지 않다는 것을 두려워하면서 여기에 내 구체적인 질문이 있습니다. 초기화 및 스크립트로드를위한 (외부) 헤드 스크립트가 있습니다. 그런 다음 본문 끝에 두 개의 정적 인라인 스크립트가 있습니다. 첫 번째 것은 스크립트 로더가 다른 스크립트 요소 (외부 js 참조)를 본문에 동적으로 추가하도록합니다. 정적 인라인 스크립트 중 두 번째는 추가 된 외부 스크립트의 js를 사용하려고합니다. 다른 사람이 실행 된 것에 의존 할 수 있습니까 (그리고 왜 :-)?


Steve Souders의 차단없이 스크립트로드 를 보았 습니까? 약간 오래된 날짜이지만 특정 스크립트 로딩 기술을 고려할 때 브라우저 동작에 대한 귀중한 통찰력이 여전히 포함되어 있습니다.
Josh Habdas

답변:


331

동적 스크립트를로드하거나 그들을 표시하지 않는 경우 defer또는 async, 다음 스크립트는 페이지에서 발생하는 순서로로드됩니다. 외부 스크립트인지 인라인 스크립트인지는 중요하지 않습니다. 페이지에서 발견 된 순서대로 실행됩니다. 외부 스크립트 다음에 오는 인라인 스크립트는 이전에 온 모든 외부 스크립트가로드되어 실행될 때까지 유지됩니다.

비동기 스크립트 (비동기 화로 지정되는 방법에 관계없이)는 예기치 않은 순서로로드 및 실행됩니다. 브라우저는 그것들을 병렬로로드하고 원하는 순서대로 자유롭게 실행할 수 있습니다.

여러 비동기 항목 중에서 예측 가능한 순서는 없습니다. 예측 가능한 순서가 필요한 경우 비동기 스크립트에서로드 알림을 등록하고 적절한 항목이로드 될 때 수동으로 javascript 호출을 시퀀싱하여 코딩해야합니다.

스크립트 태그가 동적으로 삽입되면 실행 순서는 브라우저에 따라 다릅니다. 이 참조 기사 에서 Firefox의 동작을 확인할 수 있습니다 . 간단히 말해서, 최신 버전의 Firefox는 스크립트 태그가 다르게 설정되어 있지 않으면 기본적으로 비동기로 추가 된 스크립트 태그를 비동기로 설정합니다.

스크립트 태그 async가로드 되 자마자 실행될 수 있습니다. 실제로 브라우저는 파서가 다른 작업을 중단하고 해당 스크립트를 실행할 수 있습니다. 따라서 거의 언제든지 실행할 수 있습니다. 스크립트가 캐시 된 경우 거의 즉시 실행될 수 있습니다. 스크립트를로드하는 데 시간이 걸리면 파서가 완료된 후 실행될 수 있습니다. 기억해야 할 한 가지는 async언제든지 실행할 수 있으며 그 시간은 예측할 수 없다는 것입니다.

스크립트 defer파서는 전체 파서가 완료 될 때까지 기다렸다가 표시된 defer순서대로 표시된 모든 스크립트를 실행합니다 . 이를 통해 서로 의존하는 여러 스크립트를로 표시 할 수 있습니다 defer. 문서 파서가 완료 될 때까지 모두 연기되지만, 종속성을 유지하는 순서대로 실행됩니다. defer스크립트가 파서가 완료된 후에 처리되는 대기열에 들어간 것처럼 생각 합니다. 기술적으로 브라우저는 언제든지 백그라운드에서 스크립트를 다운로드 할 수 있지만 파서가 페이지를 구문 분석하고 defer또는 로 표시되지 않은 인라인 스크립트를 구문 분석하고 실행할 때까지 파서를 실행하거나 차단하지 않습니다 async.

이 기사의 인용문은 다음과 같습니다.

스크립트 삽입 스크립트는 IE 및 WebKit에서 비동기 적으로 실행되지만 Opera 및 4.0 이전 Firefox에서는 동 기적으로 실행됩니다.

HTML5 사양의 관련 부분 (최신 호환 브라우저 용)은 여기에 있습니다 . 비동기 동작에 대해 많은 글이 있습니다. 분명히이 사양은 동작을 확인하기 위해 테스트해야 할 구형 브라우저 (또는 부적절한 브라우저)에는 적용되지 않습니다.

HTML5 사양에서 인용 한 내용 :

그런 다음 상황을 설명하는 다음 옵션 중 첫 번째 옵션을 따라야합니다.

요소에 src 속성이 있고 요소에 지연 속성이 있고 요소에 "parser-inserted"로 플래그가 지정되고 요소에 비동기 속성없는 경우 요소는 목록의 끝에 추가되어야합니다. 문서가 요소를 만든 파서의 문서와 관련된 구문 분석을 마쳤을 때 실행될 스크립트.

페치 알고리즘이 완료되면 네트워킹 태스크 소스가 태스크 큐에 배치하는 태스크는 요소의 "구문 분석기 실행 준비"플래그를 설정해야합니다. 파서는 스크립트 실행을 처리합니다.

요소에 src 속성이 있고 요소에 "parser-inserted"로 플래그가 지정되고 요소에 비동기 속성없는 경우 요소는 요소를 작성한 구문 분석기 문서의 보류중인 구문 분석 차단 스크립트입니다. (문서 당 한 번에 하나의 스크립트 만있을 수 있습니다.)

페치 알고리즘이 완료되면 네트워킹 태스크 소스가 태스크 큐에 배치하는 태스크는 요소의 "구문 분석기 실행 준비"플래그를 설정해야합니다. 파서는 스크립트 실행을 처리합니다.

요소에 src 속성이없고 요소가 "parser-inserted"로 플래그가 지정되고 스크립트 요소를 작성한 HTML 구문 분석기 또는 XML 구문 분석기의 문서에 스크립트를 차단하는 스타일 시트 가있는 경우 요소는 요소를 만든 파서의 Document에 대한 보류중인 구문 분석 차단 스크립트 (문서 당 한 번에 하나의 스크립트 만있을 수 있습니다.)

요소의 "파서 실행 준비"플래그를 설정하십시오. 파서는 스크립트 실행을 처리합니다.

요소에 src 속성이 있고 async 속성이없고 "force-async"플래그가 설정되어 있지 않은 경우 가능한 빨리 연관된 순서대로 실행할 스크립트 목록의 끝에 요소를 추가해야합니다. 스크립트 알고리즘 준비가 시작될 때 스크립트 요소의 문서와 함께.

페치 알고리즘이 완료되면 네트워킹 태스크 소스가 태스크 큐에 배치하는 태스크는 다음 단계를 실행해야합니다.

요소가 이제 스크립트 목록에서 첫 번째 요소가 아닌 경우 위에 추가 된 순서대로 실행되는 경우 요소를 준비된 것으로 표시하지만 아직 스크립트를 실행하지 않고이 단계를 중단하십시오.

실행 :이 스크립트 목록에서 첫 번째 스크립트 요소에 해당하는 스크립트 블록을 가능한 한 빨리 실행하십시오.

이 스크립트 목록에서 가능한 빨리 순서대로 실행될 첫 번째 요소를 제거하십시오.

가능한 빨리 순서대로 실행될이 스크립트 목록이 여전히 비어 있지 않고 첫 번째 항목이 이미 준비된 것으로 표시되어 있으면 실행 레이블이 지정된 단계로 건너 뜁니다.

요소에 src 속성 이있는 경우 스크립트 알고리즘 준비가 시작될 때 스크립트 요소의 문서에서 가능한 빨리 실행되는 스크립트 세트에 요소를 추가해야합니다.

페치 알고리즘이 완료되면 네트워킹 태스크 소스가 태스크 큐에 배치하는 태스크는 스크립트 블록을 실행 한 다음 가능한 빨리 실행되는 스크립트 세트에서 요소를 제거해야합니다.

그렇지 않으면 다른 스크립트가 이미 실행중인 경우에도 사용자 에이전트가 즉시 스크립트 블록을 실행해야합니다.


Javascript 모듈 스크립트는 type="module"어떻습니까?

Javascript는 이제 다음과 같은 구문으로 모듈 로딩을 지원합니다.

<script type="module">
  import {addTextToBody} from './utils.mjs';

  addTextToBody('Modules are pretty cool.');
</script>

또는 src속성이있는 경우 :

<script type="module" src="http://somedomain.com/somescript.mjs">
</script>

모든 스크립트 type="module"에는 defer속성 이 자동으로 부여됩니다 . 그러면 페이지를로드 할 때 병렬로 (인라인이 아닌 경우) 다운로드 한 다음 파서가 완료된 후 순서대로 실행됩니다.

모듈 스크립트 async에는 파서가 완료 될 때까지 기다리지 않고 async다른 스크립트에 비해 특정 순서로 스크립트 를 실행하기를 기다리지 않고 가능한 한 빨리 인라인 모듈 스크립트를 실행 하는 속성이 제공 될 수 있습니다 .

이 기사의 Javascript Module Loading 에서 모듈 스크립트를 포함하여 다양한 스크립트 조합의 페치 및 실행을 보여주는 매우 유용한 타임 라인 차트가 있습니다.


답변 주셔서 감사하지만 문제는 스크립트 페이지에 동적으로 추가되어 async로 간주 된다는 것입니다 . 아니면 <head>에서만 작동합니까? 그리고 내 경험은 문서 순서대로 실행된다는 것입니까?
Bergi

@Bergi-동적으로 추가되면 비동기이며 제어 코드를 작성하지 않으면 실행 순서가 결정되지 않습니다.
jfriend00

다만, Kolink는 말한다 ... 반대
BERGI

@ Bergi-좋아, 비동기 스크립트가 불확실한 순서로로드되도록 대답을 수정했습니다. 어떤 순서로든로드 할 수 있습니다. 내가 너라면, 코 링크의 관찰이 항상 그렇다는 것을 의지하지 않을 것이다. 동적으로 추가 된 스크립트를 즉시 실행해야하며로드 될 때까지 다른 스크립트가 실행되지 않도록 차단해야한다는 표준은 없습니다. 브라우저에 의존하고 환경 요소 (스크립트가 캐시되는지 여부 등)에 따라 달라질 것으로 기대합니다.
jfriend00

1
@RuudLenders-브라우저 구현에 달려 있습니다. 문서의 앞부분에 스크립트 태그가 있지만로 표시되어 있으면 defer구문 분석기는 실행을 연기하면서 다운로드를 더 빨리 시작할 수 있습니다. 동일한 호스트에서 많은 스크립트를 사용하는 경우 다운로드를 더 빨리 시작하면 실제로는 페이지가 대기하고있는 (같은 대역폭이 아닌 defer) 동일한 호스트에서 다른 서버의 다운로드 속도가 느려질 수 있습니다. 이것은 양날의 칼일 수 있습니다.
jfriend00

13

브라우저는 스크립트를 찾은 순서대로 실행합니다. 외부 스크립트를 호출하면 스크립트가로드되고 실행될 때까지 페이지가 차단됩니다.

이 사실을 테스트하려면 :

// file: test.php
sleep(10);
die("alert('Done!');");

// HTML file:
<script type="text/javascript" src="test.php"></script>

동적으로 추가 된 스크립트는 문서에 추가 되 자마자 실행됩니다.

이 사실을 테스트하려면 :

<!DOCTYPE HTML>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <script type="text/javascript">
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.src = "link.js"; // file contains alert("hello!");
        document.body.appendChild(s);
        alert("appended");
    </script>
    <script type="text/javascript">
        alert("final");
    </script>
</body>
</html>

경고의 순서는 "추가됨"-> "hello!"입니다. -> "최종"

스크립트에서 아직 도달하지 않은 요소 (예 :)에 액세스하려고 <script>do something with #blah</script><div id="blah"></div>하면 오류가 발생합니다.

전반적으로 예, 외부 스크립트를 포함시킨 다음 해당 함수와 변수에 액세스 할 수 있지만 현재 <script>태그 를 종료하고 새 태그를 시작하는 경우에만 가능합니다 .


그 행동을 확인할 수 있습니다. 그러나 우리의 피드백 페이지에는 test.php가 캐시 될 때만 작동 할 수있는 힌트가 있습니다. 이에 대한 사양 / 참조 링크를 알고 있습니까?
Bergi

4
link.js가 차단되지 않습니다. 긴 다운로드 시간을 시뮬레이트하려면 PHP와 비슷한 스크립트를 사용하십시오.
1983 년

14
이 답변은 잘못되었습니다. "동적으로 추가 된 스크립트가 문서에 추가 되 자마자 실행되는"경우가 항상 아닙니다. 때로는 이것이 사실입니다 (예 : Firefox의 이전 버전). 그러나 일반적으로 그렇지 않습니다. jfriend00의 답변에서 언급했듯이 실행 순서는 결정되지 않습니다.
Fabio Beltramini

1
스크립트가 인라인인지 여부에 관계없이 스크립트가 페이지에 나타나는 순서대로 실행된다는 것은 의미가 없습니다. 그렇다면 왜 Google 태그 관리자 스 니펫과 내가 본 많은 다른 사람들이 페이지의 다른 모든 스크립트 태그 위에 새 스크립트를 삽입하는 코드를 가지고 있습니까? 위의 스크립트가 이미로드 된 경우이 작업을 수행하는 것이 의미가 없습니다 ?? 아니면 뭔가 빠졌습니까?
user3094826


2

많은 옵션을 테스트 한 후 다음과 같은 간단한 솔루션이 모든 최신 브라우저에서 추가 된 순서대로 동적으로로드 된 스크립트를로드하는 것으로 나타났습니다

loadScripts(sources) {
    sources.forEach(src => {
        var script = document.createElement('script');
        script.src = src;
        script.async = false; //<-- the important part
        document.body.appendChild( script ); //<-- make sure to append to body instead of head 
    });
}

loadScripts(['/scr/script1.js','src/script2.js'])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.