이번에는 JavaScript의 비동기 로딩에 대해 자세히 설명하고, 자바스크립트 비동기 로딩을 다룰 때 주의사항은 무엇인지 살펴보겠습니다.
동기적 로딩의 문제
기본 js는 동기적으로 로딩됩니다. 최신 버전의 브라우저에서는 브라우저가 리소스를 요청하는 것이 아니라 구문 분석 및 실행으로 이해될 수 있습니다. code 차단이 아닌 모두 워터폴 로딩이지만 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 파일로 저장되는데, 페이지 본문은 단순한 string인데, 코드 실행 후에도 페이지가 공백으로 남아 있습니다. 요청한 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의 비동기 로딩을 구현하는 것입니다.
가장 일반적인 방법은 스크립트 태그를 동적으로 생성하는 것입니다.
<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 이벤트가 실행되기 전에 완료됩니다.
来看一张网上盗的图:
蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析。
此图告诉我们以下几个要点(摘自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方式等。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 JavaScript 비동기 로딩에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!