기본 js는 동기식으로 로드됩니다. 여기서 "로드"는 "다운로드"가 아닌 구문 분석 및 실행으로 이해될 수 있습니다. 브라우저는 폭포 스타일로 코드에서 요청한 리소스를 로드합니다. 차단하지는 않지만 js 실행은 항상 차단됩니다. 이로 인해 어떤 문제가 발생합니까? 인덱스 페이지에서 일부 js를 로드해야 하는데 요청 중 하나가 오랫동안 응답을 받지 못하는 경우 후속 js 코드 실행(동기 로딩)이 차단되고 페이지 렌더링이 계속될 수 없습니다(js 도입이 라벨 뒤의 헤드에 있음).
<script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> this is a test
예를 들어 위 코드는 index.html 파일로 저장되는데, 페이지 본문은 단순 문자열인데, 코드 실행 후에도 페이지가 공백으로 남아 있습니다. 요청한 js를 오랫동안 로드할 수 없기 때문에(아마도 Google이 차단되는 등의 이유로) 후속 코드의 실행이 차단되고 페이지가 렌더링될 수 없습니다. 어쩌면
앞에 js 코드를 넣으면 페이지가 먼저 렌더링될 것이라고 제안하실 수도 있습니다! 좋은 방법입니다. js를 뒤에 넣으려고 합니다.
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
페이지가 즉시 렌더링되고 "this is a test"도 빠르게 전경에 나타나며 세상은 평온해 보이지만:
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
가 앞에 있습니다. 코드를 기반으로 간단하게 코드 조각을 추가했지만 오랫동안 콘솔에 "hello world"가 출력되지 않았습니다. 분명히 이전 js 요청으로 인해 다음 코드가 로드되지 않았습니다. 갑자기 js의 로딩 위치를 변경하면 페이지 렌더링만 변경될 수 있다는 것을 깨달았습니다. 그러나 js를 로딩하는 데는 아무 소용이 없으며 js는 여전히 차단됩니다.
우리의 요구 사항은 매우 간단한 것 같습니다. 더 간단하게 말하면 Google에서 제공하는 첫 번째 js를 요청하면서 다음 js를 계속 실행합니다. , 이는 js의 비동기 로딩을 구현하는 것입니다.
가장 일반적인 방법은 스크립트 태그를 동적으로 생성하는 것입니다.
<body> this is a test <script type="text/javascript"> ~function() { var s = document.createElement('script'); s.src = 'http://china-addthis.googlecode.com/svn/trunk/addthis.js'; document.body.appendChild(s); }(); </script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </script> </body>
그러나 여전히 문제가 있습니다. 이 로딩 방법은 로딩이 완료되기 전에 onload 이벤트가 트리거되는 것을 방지합니다. 여전히 로드 중입니다. 추가 렌더링 작업 등을 수행해야 하므로 일부 페이지의 초기화 처리가 계속 차단됩니다.
<body> this is a test <script type="text/javascript"> ~function() { // function async_load() { var s = document.createElement('script'); s.src = 'http://china-addthis.googlecode.com/svn/trunk/addthis.js'; document.body.appendChild(s); // } // window.addEventListener('load', async_load, false); }(); window.onload = function() { var txt = document.createTextNode(' hello world'); document.body.appendChild(txt); }; </script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> </body>
예를 들어 위 코드는 "hello world"를 제대로 렌더링할 수 없습니다. 주석을 제거하고 Google에서 제공된 js가 onload 시에만 비동기식으로 로드되기 시작하도록 합니다. 이는 onload 이벤트가 트리거되는 것을 차단하는 문제를 해결합니다.
DOMContentLoaded 및 OnLoad 이벤트 추가 DOMContentLoaded: 페이지(문서)가 구문 분석되었으며 페이지의 dom 요소를 사용할 수 있습니다. 그러나 페이지에서 참조된 이미지와 하위 프레임이 아직 로드되지 않았을 수 있습니다. OnLoad: 페이지의 모든 리소스가 로드됩니다(이미지 포함). 이 시점에서 브라우저의 로딩 진행이 중지됩니다. 이 두 시점은 페이지 로딩 타임라인을 세 단계로 나눕니다.
위의 방법이 이 문제에 대한 더 나은 해결책인 것처럼 보이지만 html5는 더 간단한 방법인 async 속성을 제공합니다!
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' async='async'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </script>
async는 HTML5의 새로운 속성입니다. async 속성은 스크립트를 사용할 수 있게 되면 비동기적으로 실행되도록 규정합니다(다운로드되는 즉시 실행됩니다).
async 속성은 외부 스크립트에만 적용된다는 점에 유의해야 합니다(src 속성을 사용하는 경우에만)
defer 속성은 종종 async와 함께 언급됩니다:
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' defer='defer'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script> <script type="text/javascript"> console.log('hello world'); </script>
구현 효과는 비슷한 것 같습니다, 하지만 정말 똑같을까? defer 속성의 정의를 살펴보겠습니다.
과거에는 Defer가 IE Hack만 지원했지만 이제 HTML5의 등장으로 Defer를 완벽하게 지원하기 시작했습니다. defer 속성은 페이지 로딩이 완료될 때까지 스크립트가 실행되지 않도록 지정합니다. defer 속성은 외부 스크립트에만 적용됩니다(src 속성을 사용하는 경우에만). ps: IE에서 지원하는 지연은 해당되지 않는 것 같습니다. 왜냐하면 저는 IE에 관심이 없고 이에 대해 자세히 알아보지 않을 것이기 때문입니다. 관심이 있으시면 관련 정보를 확인하실 수 있습니다.
async와 defer는 자주 함께 등장하므로 분석해보겠습니다!
비동기 및 지연 속성이 없으면(true로 지정됨, 아래와 같음) 비동기 속성이 있으면 브라우저는 즉시 현재 js 스크립트를 실행하고 후속 스크립트를 차단합니다. 후속 문서 요소를 로드하고 렌더링하는 프로세스는 다음과 같습니다. 현재 js와 동일해야 합니다. script.js의 로딩과 실행은 병렬(비동기)로 수행됩니다. defer 속성이 있는 경우 후속 문서 요소를 로드하는 프로세스는 script.js의 로딩과 병렬로 수행됩니다( 비동기), script.js의 실행은 모든 요소(DOM)가 구문 분석된 후에 완료되어야 하며 그 후에는 DOMContentLoaded 이벤트가 실행되기 전에 완료됩니다.
인터넷에서 훔친 사진을 살펴보겠습니다.
파란색 선은 네트워크 읽기를 나타내고 빨간색 선은 실행 시간을 나타내며 둘 다 스크립트용입니다.
이 그림은 다음과 같은 핵심 사항을 알려줍니다(defer와 async의 차이에서 추출):
defer와 async는 네트워크 읽기(다운로드) 측면에서 동일하며 둘 다 비동기적입니다(HTML 구문 분석과 비교).
두 가지의 차이점은 스크립트가 다운로드된 후 실행되는 시점에 있습니다. 분명히 defer는 애플리케이션 스크립트 로드 및 실행에 대한 요구 사항에 가장 가깝습니다
关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用
async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行
仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics
但是在我看来(以下个人理解,如有出入还望指出),defer在异步加载上的应用并不会比async广。async的英文解释是异步,该属性作用在脚本上,使得脚本加载(下载)完后随即开始执行,和动态插入script标签作用类似(async只支持h5,后者能兼容浏览器);而defer的英文解释是延迟,作用也和字面解释类似,延迟脚本的执行,使得dom元素加载完后才开始有序执行脚本,因为有序,所以会带来另一个问题:
this is a test <script type="text/javascript" src='http://china-addthis.googlecode.com/svn/trunk/addthis.js' defer='defer'></script> <script type="text/javascript" src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js' defer='defer'></script> <script type="text/javascript" src='index.js' defer='defer'></script> console.log('hello world');
如果执行这段代码,控制台的“hello world”也会迟迟得不到结果。所以我觉得还是async好用,如果要考虑依赖的话,可以选择requirejs、seajs等模块加载器。
JavaScript的异步加载还有一些方式,比如:AJAX eval(使用AJAX得到脚本内容,然后通过eval(xmlhttp.responseText)来运行脚本)、iframe方式等。
相关推荐:
위 내용은 여러 JavaScript 비동기 로딩 관련 문제의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!