jQuery 초기화 함수인 jQuery.fn.init에 브랜치가 있다는 걸 아직도 기억하시나요
//document ready简便写法$(function(){…}) } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } 所以$(fn)===$(document).ready(fn)。 来看一下jQuery.fn.ready的源码 ready: function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); return this; }
jQuery.ready.promise 함수에 지연이 설정되어 있고 지연 객체가 해결되면 fn 함수가 실행되는 것은 당연합니다.
주요 처리 흐름:
지연 객체를 생성하고 문서 준비가 완료된 후 처리 이벤트를 지연 객체의 성공 이벤트 목록에 추가합니다.
jQuery.ready.promise = function( obj ) { if ( !readyList ) { readyList = jQuery.Deferred(); ... } return readyList.promise( obj ); }
문서 준비 상태에 대한 수신 기능 추가(jQuery.ready.promise 함수 조각)
//标准浏览器支持DOMContentLoaded事件 } else if ( document.addEventListener ) { //绑定DOMContentLoaded事件和响应函数,响应函数会解决延时 document.addEventListener( "DOMContentLoaded", completed, false ); //回退到window.onload事件绑定,所有的浏览器都支持 window.addEventListener( "load", completed, false ); //如果是IE事件模型 } else { //确保在onload之前执行延时,可能时间比较迟,但是对于iframes来说比较安全 document.attachEvent( "onreadystatechange", completed ); //回退到window.onload事件绑定,所有的浏览器都支持 window.attachEvent( "onload", completed ); //如果IE并且不是一个frame //不断地检查,看是否该文件已准备就绪 var top = false; try { top = window.frameElement == null && document.documentElement; } catch(e) {} if ( top && top.doScroll ) { (function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } //移除之前绑定的事件 detach(); //执行延迟 jQuery.ready(); } })(); } }
문서가 준비된 것으로 감지되면 jQuery.ready를 호출하여 지연 객체의 성공 콜백 목록을 실행합니다. 즉, jQuery.ready(fn) [또는 jQuery(fn)]를 통해 추가된 모든 함수 fn입니다.
//ready事件处理函数 completed = function( event ) { // readyState === "complete"在老版本IE上适用 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { detach(); jQuery.ready(); } }, //清除ready事件绑定 detach = function() { if ( document.addEventListener ) { document.removeEventListener( "DOMContentLoaded", completed, false ); window.removeEventListener( "load", completed, false ); } else { document.detachEvent( "onreadystatechange", completed ); window.detachEvent( "onload", completed ); } }; //处理当DOM准备完成 jQuery.ready: function( wait ) { ... //设置DOM已经准备好的标志 jQuery.isReady = true; ... //执行绑定的延时事件 readyList.resolveWith( document, [ jQuery ] ); //触发任何绑定的就绪事件 if ( jQuery.fn.trigger ) { jQuery( document ).trigger("ready").off("ready"); } }
이것이 전체 과정입니다. 정리해야 할 몇 가지 작은 지식 포인트가 있습니다.
a. 문서 로딩 상태 document.readyState
Document.readyState는 문서 로딩 상태를 결정하는 데 사용됩니다. 가능한 값은 다음과 같습니다.
0-uninitialized: XML 객체가 생성되지만 파일이 로드되지 않습니다.
1-loading: 로딩 프로그램이 진행 중이지만 파일 분석이 아직 시작되지 않았습니다.
2-로드: 일부 파일이 로드되고 구문 분석되었지만 개체 모델이 아직 적용되지 않았습니다.
3-대화형: 로드된 파일의 일부에만 유효합니다. 이 경우 개체 모델은 유효하지만 읽기 전용입니다.
4-complete: 파일이 완전히 로드되었습니다. 이는 로드가 성공했음을 의미합니다.
예:
document.onreadystatechange = stateChange;//当页面加载状态改变的时候执行这个方法. function stateChange() { if(document.readyState == "complete"){ //当页面加载状态为完全结束时进入 alert("文档加载成功") } }
하지만 이전 버전의 Firefox에서는 document.readyState를 지원하지 않습니다. [최신 Firefox에서는 이미 지원하고 있습니다.] 따라서 모든 브라우저와 호환되려면 두 가지 상황에서 모니터링 문서 작성을 진행해야 합니다.
- 표준 브라우저는 addEventListener를 사용하여 DOMContentLoaded를 추가하고 리스너를 로드하며 모든 이벤트가 트리거될 수 있습니다.
- 이전 버전의 IE 브라우저는 attachmentEvent를 사용하여 onreadystatechange 및 onload를 모니터에 추가하고, 어느 것이든 트리거되며, onreadystatechange 시 document.readyState === "complete"입니다.
jQuery에서는 이렇게 처리합니다
jQuery.ready.promise = function(){ ... //标准浏览器支持DOMContentLoaded事件 else if ( document.addEventListener ) { //绑定DOMContentLoaded事件和响应函数,响应函数会解决延时 document.addEventListener( "DOMContentLoaded", completed, false ); //回退到window.onload事件绑定,所有的浏览器都支持 window.addEventListener( "load", completed, false ); //如果是IE事件模型 } else { //确保在onload之前执行延时,可能时间比较迟,但是对于iframes来说比较安全 document.attachEvent( "onreadystatechange", completed ); //回退到window.onload事件绑定,所有的浏览器都支持 window.attachEvent( "onload", completed ); ... } } //ready事件处理函数 completed = function( event ) { // readyState === "complete"在老版本IE上适用 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { detach(); jQuery.ready(); } }
b.doScroll이 문서 로딩 완료를 감지합니다
이것은 IE가 로드되었는지 감지하기 위해 Diego Perini가 발견한 방법입니다. 상세링크
페이지 DOM이 로드되지 않은 경우 doScroll 메소드 호출 시 예외가 발생하는 것이 원칙입니다. 그러면 예외 발생 여부를 지속적으로 확인하여 문서가 로드되었는지 알 수 있습니다. 예외가 발생하지 않으면 문서 로딩이 완료된 것입니다. ~
(function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } //移除之前绑定的事件 detach(); //执行延迟 jQuery.ready(); } })();