Quickeryi / note

学习记录
2 stars 0 forks source link

浅谈dom.ready,JS原生实现jQuery.ready #12

Open Quickeryi opened 7 years ago

Quickeryi commented 7 years ago

jQuery的ready方法执行的时机是在DOM准备就绪后,而不是不是等待所有资源加载完毕,即onload事件触发时执行

dom.ready

需要清楚dom什么时候ready,需要先知道浏览器整个渲染步骤:

而根据Navigation Timing API可以更加清晰的知道在上述整个过程中,页面逐步触发的事件信息:

结论:所以 dom ready 发生在 domContentLoaded 阶段

兼容性

根据上述理论,我们知道dom ready 发生的时机,但是不同的浏览器在此时机的表现不同,或者说开发者通过js获取dom ready状态的方法不同

jQuery.ready 实现

有了上述理论分析,我们贴出原生的jQuery.ready实现

let ready = (fn) => {
    let completed = () => {
         if (document.addEventListener) {
             document.removeEventListener('DOMContentLoaded', completed, false);
             window.removeEventListener('load', completed, false);
          } else if (document.attachEvent) {
              document.detachEvent('onreadystatechange', completed);
              window.attachEvent('onload', completed);
          }
          fn();
     };

      /**
        * 如果我们注册 ready 函数的时间点太晚了,页面已经加载完成之后,那么直接执行 fn
        */
      if (document.readyState == 'complete') {
           setTimeout(fn, 1);
      } else if (document.addEventListener) {
           document.addEventListener('DOMContentLoaded', completed, false);

            // 当触发不了 DOMContentLoaded 时,只能优雅降级
            window.addEventListener('load', completed, false);
      } else { // IE
           document.attachEvent('onreadystatechange', completed);
           window.attachEvent('onload', completed);

            // If IE and not a frame
            let top = false;
               try {
                   top = window.frameElement == null && document.documentElement;
                } catch(e) {}

               if (top && top.doScroll) {
                   (function doScrollCheck() {
                        try {
                            top.doScroll("left");
                        } catch (e) {
                            return setTimeout(doScrollCheck, 50)
                        }
                        fn();
                    })();
               }
        }
};