[javascript] 스크립트 순서로드 및 실행

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를 사용하려고합니다. 다른 사람이 실행 된 것에 의존 할 수 있습니까 (그리고 왜 :-)?



답변

동적 스크립트를로드하거나 그들을 표시하지 않는 경우 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 에서 모듈 스크립트를 포함하여 다양한 스크립트 조합의 페치 및 실행을 보여주는 매우 유용한 타임 라인 차트가 있습니다.


답변

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

이 사실을 테스트하려면 :

// 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>태그 를 종료하고 새 태그를 시작하는 경우에만 가능합니다 .


답변

@addyosmani 의 훌륭한 요약

여기에 이미지 설명을 입력하십시오

https://addyosmani.com/blog/script-priorities/ 에서 뻔뻔스럽게 복사


답변

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

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'])


답변