• Dom加载让图片加载完再执行


    说点javascript的加载、解析、执行对浏览器渲染的影响

    javascript的加载方式,总得来说是在页面上使用script来声明,以及动态的加载这些方式,而动态的加载,在很多js库中都能够很好的去处理,从而不至于阻塞其他资源的加载,并与其并行加载下来。这样的动态异步的加载方式罗列起来有:Ajax的方式、DOM Element Insert、Iframe、document.write、defer等等。这些都能够很好的处理js在加载的时候不会阻塞资源加载的问题,但是,js的执行仍然会阻塞浏览器的渲染。或许这是不得不需要付出的代价,有没有一些方式去缓解js在执行的时候对浏览器的渲染所造成的延迟的影响呢?

    首先,让我们从UI Thread、UI Queue、UI Upate的角度去分析整个页面和javascript的行为。浏览器在加载HTML到最后呈现出来的这段过程,整个就是一个UI Thread进程,这个UI Thread里是一个浏览器的响应队列,而UI Queue则是浏览器的行为队列,包括UI Update,javascript的执行行为。那么在页面加载的过程中,UI Queue里面就储存了UI Update、js加载、js解析、js执行等。不管是UI Thread,还是UI Queue,都是按照顺序来的。页面在刚开始未遇到js的加载和执行的时候,是UI Update的一个过程,一旦遇到js,就会等待js的加载、解析、执行完毕之后,接着又开始UI Update,如此这样的一个相应顺序。

    那么当js的加载是异步了之后呢,这个时候,js的加载和解析不会在UI Queue的执行队列里,而是等到js加载、解析完毕,一到执行的时候,就添加到UI Queue队列中,从而阻塞了UI Queue中后面的行为(UI Update)的执行。这就是开头所说的在js的执行期总会阻塞页面的渲染,也就是UI Update。但是这个动态加载的方式跟普通在页面中使用script标签来加载的时候的优势是:将js的加载、解析的行为独立出来,不影响浏览器的UI Update,知道执行期才阻塞。这就很多的程度上加快了页面的渲染和展现。

    再来说说defer和async属性,defer属性最开始是为IE所实现的,现代的浏览器也都逐渐实现了,那么它的工作原理是什么呢。它的作用跟上面动态加载的优势很相同,js的加载和解析是独立的,但是有一点不同的是:使用了defer属性之后,js代码会等到DOM加载完成的时候才执行,这个时候就又更大限度的让浏览器尽快的UI Update部分完成,让js的执行对浏览器的渲染所造成的影响更小化。那么async呢,是跟上面所说的动态加载js的优势是一样的,也是独立js的加载、解析,解析完成的时候就立即添加到UI Queue队列中去等待执行,阻塞后面的UI Update行为。

    那么怎样将js的执行对UI Update的影响更小呢?使用HTML5的Worker机制吧,将复杂的js执行交给Worker去执行,Worker是一个独立的js执行环境,这个环境里没有window、DOM的概念,只是用来处理复杂的运算,再将处理后的结果通过postMessage方法发送会浏览器,Worker和页面之间通过postMessage方法来实现跟浏览器的数据交换。这样,将复杂运算交给Worker之后,在页面中所执行的js代码,将会是大大的减小,减小到只需要处理一个onmessage事件,将页面的js执行时间最小化。

    杯具的还是defer、async、Worker还不能够完全的被目前市面上流行的浏览器所兼容,期待浏览器统一的那一天。

    当大家使用window.onload执行一个函数时,必须要等到页面上的图片等信息全部加载完毕之后才执行的。但很多时候图片的数量比较多,所以需要很多时间下载。更令人尴尬的是,当网页文档(或者说Dom)已经加载完毕,而图片尚未加载完毕,很多用户已经开始浏览网页,但这时很多由window.onload所触发的函数不能执行,这就导致一部分功能不能完美地给用户使用,更严重的是会给用户留下不好的印象! 


    现在,我们来研究一下如何解决这个问题,解决方法就是在DOM加载完毕之后就执行程序。 

           先介绍两个人。一,jquery的作者:John Resig;二,javascript的世界级大师:dean edwards。(大家要记住这两位天才!) 

          jquery里有专门解决DOM加载的函数$(document).ready()(简写就是$(fn)),非常好用!John Resig在《Pro JavaScript Techniques》里,有这样一个方法处理DOM加载,原理就是通过document&& document.getElementsByTagName &&document.getElementById&& document.body 去判断Dom树是否加载完毕。代码如下:

    function domReady( f ) {

    // 如果DOM加载完毕,马上执行函数if ( domReady.done ) return f();   
    // 假如我们已增加一个函数
    if ( domReady.timer ) { 
    // 把它加入待执行的函数清单中
    domReady.ready.push( f ); 
    else { 
    // 为页面加载完成绑定一个事件, 
    // 为防止它最先完成. 使用 addEvent(下面列出).
    addEvent( window, “load”, isDOMReady );   
    // 初始化待执行的函数的数组
    domReady.ready = [ f ];   
    // 经可能快地检查Dom是否已可用
    domReady.timer = setInterval( isDOMReady, 13 ); 

    }  
    // 检查Dom是否已可操作
    function isDOMReady() { 
    // 假如已检查出Dom已可用, 忽略 
    if ( domReady.done ) return false;   
    // 检查若干函数和元素是否可用
    if ( document &&  document.getElementsByTagName &&  document.getElementById &&  document.body ) {   
    // 假如可用, 停止检查
    clearInterval( domReady.timer ); 
    domReady.timer = null;   
    // 执行所有等待的函数
    for ( var i = 0; i < domReady.ready.length; i++ ) 
    domReady.ready[i]();   
    // 记录在此已经完成
    domReady.ready = null
    domReady.done = true

    }
    // 由 Dean Edwards 在2005 所编写addEvent/removeEvent,
    // 由 Tino Zijdel整理
    // http://dean.edwards.name/weblog/2005/10/add-event/
    //优点是1.可以在所有浏览器工作;
    //2.this指向当前元素;
    //3.综合了所有浏览器防止默认行为和阻止事件冒泡的的函数
    //缺点就是仅在冒泡阶段工作
    function addEvent(element, type, handler) {
        // assign each event handler a unique ID
        if (!handler.$$guid) handler.$$guid = addEvent.guid++;
        // create a hash table of event types for the element
        if (!element.events) element.events = {};
        // create a hash table of event handlers for each element/event pair
        var handlers = element.events[type];
        if (!handlers) {
            handlers = element.events[type] = {};
            // store the existing event handler (if there is one)
            if (element["on" + type]) {
                handlers[0] = element["on" + type];
            }
        }
        // store the event handler in the hash table
        handlers[handler.$$guid] = handler;
        // assign a global event handler to do all the work
        element["on" + type] = handleEvent;
    };
    // a counter used to create unique IDs
    addEvent.guid = 1;
    function removeEvent(element, type, handler) {
        // delete the event handler from the hash table
        if (element.events && element.events[type]) {
            delete element.events[type][handler.$$guid];
        }
    };
    function handleEvent(event) {
        var returnValue = true;
        // grab the event object (IE uses a global event object)
        event = event || fixEvent(window.event);
        // get a reference to the hash table of event handlers
        var handlers = this.events[event.type];
        // execute each event handler
        for (var i in handlers) {
            this.$$handleEvent = handlers[i];
            if (this.$$handleEvent(event) === false) {
                returnValue = false;
            }
        }
        return returnValue;
    };
    function fixEvent(event) {
        // add W3C standard event methods
        event.preventDefault = fixEvent.preventDefault;
        event.stopPropagation = fixEvent.stopPropagation;
        return event;
    };
    fixEvent.preventDefault = function() {
        this.returnValue = false;
    };
    fixEvent.stopPropagation = function() {
        this.cancelBubble = true;
    };

    //

    还有一个估计由几个外国大师合作写的,实现同样功能。 
    /*
    * (c)2006 Jesse Skinner/Dean Edwards/Matthias Miller/John Resig
    * Special thanks to Dan Webb's domready.js Prototype extension
    * and Simon Willison's addLoadEvent
    *
    * For more info, see:
    * http://www.thefutureoftheweb.com/blog/adddomloadevent
    * http://dean.edwards.name/weblog/2006/06/again/
    * http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype
    * http://simon.incutio.com/archive/2004/05/26/addLoadEvent

    *
    * To use: call addDOMLoadEvent one or more times with functions, ie:
    *
    *    function something() {
    *       // do something
    *    }
    *    addDOMLoadEvent(something);
    *
    *    addDOMLoadEvent(function() {
    *        // do other stuff
    *    });
    *
    */

    addDOMLoadEvent = (function(){
        // create event function stack
        var load_events = [],
            load_timer,
            script,
            done,
            exec,
            old_onload,
            init = function () {
                done = true;
                // kill the timer
                clearInterval(load_timer);
                // execute each function in the stack in the order they were added
                while (exec = load_events.shift())
                    exec();
                if (script) script.onreadystatechange = '';
            };
        return function (func) {
            // if the init function was already ran, just run this function now and stop
            if (done) return func();
            if (!load_events[0]) {
                // for Mozilla/Opera9
                if (document.addEventListener)
                    document.addEventListener("DOMContentLoaded", init, false);
                // for Internet Explorer
                /*@cc_on @*/
                /*@if (@_win32)
                    document.write("<script id=__ie_onload defer src=//0><\/scr"+"ipt>");
                    script = document.getElementById("__ie_onload");
                    script.onreadystatechange = function() {
                        if (this.readyState == "complete")
                            init(); // call the onload handler
                    };
                /*@end @*/
                // for Safari
                if (/WebKit/i.test(navigator.userAgent)) { // sniff
                    load_timer = setInterval(function() {
                        if (/loaded|complete/.test(document.readyState))
                            init(); // call the onload handler
                    }, 10);
                }
                // for other browsers set the window.onload, but also execute the old window.onload
                old_onload = window.onload;
                window.onload = function() {
                    init();
                    if (old_onload) old_onload();
                };
            }
            load_events.push(func);
        }
    })();


  • 相关阅读:
    老陈与小石头运算代码
    第五次作业
    老陈与小石头
    简易四则运算
    四则运算
    对git的认识
    第一次作业
    arcgis-tomcat-cors
    jquery deferred promise
    springloaded hot deploy
  • 原文地址:https://www.cnblogs.com/bluespot/p/2797191.html
Copyright © 2020-2023  润新知