Jquery 擴展方法實現原理

JSONP原理

  首先:JSON和JSONP是不同的概念。javascript

  JSON是一種數據交換格式,而JSONP是非正式傳輸協議。css

  該協議的一個要點就是容許用戶傳遞一個callback參數給服務端,而後服務端返回數據時會將這個callback參數做爲函數名來包裹住JSON數據,這樣客戶端就能夠隨意定製本身的函數來自動處理返回數據。html

  其實現細節是使用 Script標籤攜帶一個Callback函數,動態的向服務端請求數據。java

  如:   jquery

<script type="text/javascript">    
    var searchCallback = function (data) {
        console.log(data)
    }
    var url = "http://demo.com/jsonp/search?id=1&callback=searchCallback";
    // 建立script標籤,設置其屬性
    var script = document.createElement('script');
    script.setAttribute('src', url);
    // 把script標籤加入head,此時調用開始
    document.getElementsByTagName('head')[0].appendChild(script);
</script>

  結論:

  在jquery 源碼中, jsonp的實現方式是動態添加<script>標籤來調用服務器提供的 js腳本。jquery 會在window對象中加載一個全局的函數,當 <script>代碼插入時函數執行,執行完畢後就<script>會被移除。ajax


Delegate原理

  早期版本中叫delegate, 後來有過live函數,再後來統一用on。下面的方法等效json

    // jQuery 1.3
    $(selector).(events, data, handler);
    // jQuery 1.4.3+
    $(elements).delegate(selector, events, data, handler);
    // jQuery 1.7+ live過期 舊版本的jQuery中用戶,應優先使用.delegate()來取代.live()
    $(elements).on(events, selector, data, handler);

  在3.0之後統一使用on.跨域

  說到Delegate原理須要首先了解二個概念:事件捕獲和事件冒泡promise

  

  

    • 事件捕獲:當某個元素觸發某個事件(如onclick),頂層對象document就會發出一個事件流,隨着DOM樹的節點向目標元素節點流去,直到到達事件真正發生的目標元素。在這個過程當中,事件相應的監聽函數是不會被觸發的。
    • 事件目標:當到達目標元素以後,執行目標元素該事件相應的處理函數。若是沒有綁定監聽函數,那就不執行。
    • 事件冒泡:從目標元素開始,往頂層元素傳播。途中若是有節點綁定了相應的事件處理函數,這些函數都會被一次觸發。若是想阻止事件冒泡,可使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)來組織事件的冒泡傳播。

  源碼片斷以下:  瀏覽器

jQuery.fn.extend( {
        ...
	delegate: function( selector, types, data, fn ) {
		return this.on( types, selector, data, fn );
	},
	...
} );

function on( elem, types, selector, data, fn, one ) {
        ...        
        return elem.each( function() {
		jQuery.event.add( this, types, fn, data, selector );
	} );
}

jQuery.event = {
    ...
    add: function( elem, types, handler, data, selector ) {
... // 若未指定特殊的事件處理,則使用addEventListener if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle ); } }
... } ... }

   如下是相似綁定的對比(後期綁定:元素已經加載後,進行事件的綁定。前期綁定:元素還沒有存在,爲動態元素添加事件):

    • bind是在dom樹加載後,對元素的綁定,屬於後期綁定。
    • one是在dom樹加載後,對元素的綁定,和bind同樣屬於後期綁定,可是會在事件執行以後移除元素的綁定事件,事件只執行一次。
    • live 是先把事件綁定在document對象上面,經過事件冒泡,判斷當前處於目標狀態的元素是否是預綁定的那個元素對象,而後執行事件,屬於前期綁定,元素能夠是已存在的,也能夠是動態添加的。
    • delegate綁定的元素能夠是已經存在的,也能夠是動態添加的。若是是已經存在的就會選定一個父元素,經過冒泡來觸發指定子元素的事件。若是是動態添加的,就以document爲父元素來觸發冒泡事件。

  結論:

  Jquery使用事件冒泡(作了兼容性處理),經過addEventListener到父元素進行事件監聽,經過e.target判斷觸發元素。

 

Data原理

  做用: Jquery.data() 方法向被選元素附加數據,或者從被選元素獲取數據。

  Jquery在原型和構造上均有data方法,jQuery.extend 與 jQuery.fn.extend 的區別在於:

    • jQuery.extend 是在 jQuery 這個構造函數上擴展的方法,調用的時候寫成 $.xxx 或者 jQuery.xxx
    • jQuery.fn.extend 是在 jQuery 原型上擴展的方法,原型上的方法被全部 jQuery 對象共享,調用的時候爲 $().xxx

  Jquery經過全局對象 cache 來保存 dom 元素上綁定的數據,能夠避免 dom 對象和 js 對象之間互相引用致使的循環引用問題。

  在內部實現上,Jquery經過使用一個隨機數做爲主鍵添加到元素上並附加一個index number。使用cache來進行查找。

  如:

$("#header").data("title", "hello world");
// 執行後打印 $.cache 結果爲
{
    1: {
        data: {
            title : "hello world"
        }
    }
}
// 查看 header 元素,發現屬性中多了一行 
//"jQuery18102873769768048078: 1"
//其中 key 值那一長串爲 jQuery 實例惟一標識,1 是 header 元素綁定的數據在 cache 對象中對應的屬性名,該值每次增長 1,
$("#header").data("title");

  結論:

  Jquery.data在內部使用全局cache進行數據緩存,並未把實際數據添加到元素上。而是使用隨機數做爲屬性名,自增數字做爲值。在獲取時根據以上匹配全局緩存。

 

Ajax原理

  Ajax:Asynchronous JavaScript and XML。在不重載整個網頁的狀況下,AJAX 經過後臺加載數據,並在網頁上進行顯示。

  Jquery在實現Ajax時,對不一樣dataType的採用了不一樣的實現方式。dataType有:xml,html,script,json,jsonp,text。

  經過查看源碼能夠知道,Jquery中定義了二個全局變量:prefilters,預處理器,在ajax請求發出以前作預處理工做;transports,分發器,負責實際發送ajax請求。

  ajax會在每一個請求發送前,根據datatype調用prefilters中的對應函數進行預處理,而後調用transports中的對應函數來發送請求。

  主要流程以下:

1,建立jqXHR對象,這個對象就是ajax的返回值
2,用deferred對象封裝jqXHR對象,所以能夠實現鏈式的異步操做:xhr.complete(x).success(x).errorl(x),這裏的complete,success和error就是promise對象的add, done和fail的別名而已。
3,調用函數inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ),那些插件註冊的prefilters函數就在這裏被調用了。
4,後續處理,好比設置header參數,設置緩存cache
5,調用inspectPrefiltersOrTransports( transports, s, options, jqXHR )函數發送請求
6,定義了done函數,當請求發送結束以後作後續處理,包括調用convert轉換結果、設置statusText,調用deferred.resolveWith觸發異步回調等
7,最後返回了jqXHR對象

  結論:

    Jquery中的插件實現提供了二種方式:

    跨域/Script/Jsonp對應使用Script標籤

    普通請求使用XMLHttpRequest對象  


Trigger原理

  Jquery源碼事件流程圖以下(引用自here):

  源碼片斷以下:

  

jQuery.extend( jQuery.event, {

    trigger: function( event, data, elem, onlyHandlers ) {
            ...
            // Fire handlers on the event path
        i = 0;
        while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
            lastElement = cur;
            event.type = i > 1 ?
                bubbleType :
                special.bindType || type;

            // jQuery handler
            handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
                dataPriv.get( cur, "handle" );
            if ( handle ) {
                handle.apply( cur, data );
            }

            // Native handler
            handle = ontype && cur[ ontype ];
            if ( handle && handle.apply && acceptData( cur ) ) {
                event.result = handle.apply( cur, data );
                if ( event.result === false ) {
                    event.preventDefault();
                }
            }
        }
        event.type = type;     
      // If nobody prevented the default action, do it now
        if ( !onlyHandlers && !event.isDefaultPrevented() ) {
      ...      
        if ( event.isPropagationStopped() ) {
               lastElement.addEventListener( type, stopPropagationCallback );
            }
              elem[ type ]();//執行默認行爲,好比:input[submit](),input元素的提交方法。點擊類型爲submint的input,會默認執行submit屬性方法。可是這裏不會調用dispatch方法。
             if ( event.isPropagationStopped() ) {
                 lastElement.removeEventListener( type, stopPropagationCallback );
             }
      ...
      }
        ...
    }
}

 

  結論:

  獲取事件句柄,經過apply方法調用定義的回調函數。並執行默認行爲。  

  

  triggerHandler

  相似於trigger,可是不會觸發元素的默認行爲,例如a標籤的跳轉行爲,submit的提交行爲等,且不會在DOM樹中冒泡,所以事件不會傳遞給它的任何祖輩元素  


Animate原理

  源碼片斷以下:

jQuery.fn.extend({
    animate: function (prop, speed, easing, callback) {
        ...
        doAnimation = function () {
            // Operate on a copy of prop so per-property easing won't be lost
            var anim = Animation(this, jQuery.extend({}, prop), optall);

            // Empty animations, or finishing resolves immediately
            if (empty || dataPriv.get(this, "finish")) {
                anim.stop(true);
            }
        ...        
        };
    }
)

function Animation( elem, properties, options ) {
    ...
    jQuery.fx.timer(
        jQuery.extend( tick, {
            elem: elem,
            anim: animation,
            queue: animation.opts.queue
        } )
    );
    ...
}

jQuery.fx.timer = function( timer ) {
    jQuery.timers.push( timer );
    jQuery.fx.start();
};

jQuery.fx.start = function() {
    if ( inProgress ) {
        return;
    }
    inProgress = true;
    schedule();
};

function schedule() {
    if ( inProgress ) {
        if ( document.hidden === false && window.requestAnimationFrame ) {
            window.requestAnimationFrame( schedule );
        } else {
            window.setTimeout( schedule, jQuery.fx.interval );
        }
        jQuery.fx.tick();
    }
}

  結論:

  根據以上片斷,能夠直擊最終實現,在支持window.requestAnimationFrame的瀏覽器上,經過requestAnimationFrame調用。

  在不支持以上方式的瀏覽器上,經過定時器按interval頻率觸發元素改變。  

  優勢:在不支持CSS3動畫的瀏覽器上實現動畫效果。


Ready原理

  源碼片斷以下:

// Catch cases where $(document).ready() is called
// after the browser event has already occurred.
// Support: IE <=9 - 10 only
// Older IE sometimes signals "interactive" too soon
if ( document.readyState === "complete" ||
	( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {

	// Handle it asynchronously to allow scripts the opportunity to delay ready
	window.setTimeout( jQuery.ready );

} else {

	// Use the handy event callback
	document.addEventListener( "DOMContentLoaded", completed );

	// A fallback to window.onload, that will always work
	window.addEventListener( "load", completed );
}

// The ready event handler and self cleanup method
function completed() {
	document.removeEventListener( "DOMContentLoaded", completed );
	window.removeEventListener( "load", completed );
	jQuery.ready();
}
 

  結論:

  二種實現方式: 1,標準瀏覽器採用監聽 DOMContentLoaded事件,完成後調用定義的回調函數; 2,IE採用試圖滾動頁面,能滾動了就證實加載好了並進行回調。


Deferred原理

  Deferreds 能夠理解爲表示須要長時間才能完成的耗時操做的一種方式,相比於阻塞式函數它們是異步的,而不是阻塞應用程序等待其完成而後返回結果。 deferred對 象會當即返回,而後你能夠把回調函數綁定到deferred對象上,它們會在異步處理完成後被調用。

jQuery.extend({

    Deferred: function (func) {
    ...
    promise = {
        state: function () {
            return state;
        },
        always: function () {
            deferred.done(arguments).fail(arguments);
            return this;
        },
        "catch": function (fn) {
            return promise.then(null, fn);
        },

        then: function (onFulfilled, onRejected, onProgress) {
        ...
			},
    deferred = {}; 
    // Make the deferred a promise
    promise.promise(deferred);
    // Call given func if any
    if (func) {
        func.call(deferred, deferred);
    }

    // All done!
    return deferred;
    }
}

  結論:

  總的來說Deferred經過一組 API 來規範化異步操做,讓異步操做的流程控制更加容易。


Lazyload原理

  核心:按需加載

  插件:jquery.lazyload.js

  源代碼片斷以下:

function update() {
    elements.each(function () {      
       ...
    //判斷當前視窗與設置的關係 if (!$.belowthefold(this, settings) && !$.rightoffold(this, settings)) { $this.trigger("appear"); } ... }); } /* 符合條件時,顯示圖片 */ $self.one("appear", function () { if (!this.loaded) { $("<img />") .bind("load", function () { var original = $self.attr("data-" + settings.data_attribute); $self.hide(); if ($self.is("img")) { $self.attr("src", original); } else { $self.css("background-image", "url('" + original + "')"); } ... }) .attr("src", $self.attr("data-" + settings.data_attribute)); } });

  結論:

  根據配置,監聽事件觸發(Scroll等),判斷圖片是否在可見區域(接近),經過設置其src屬性值爲original中真實值,以加載圖片。

 

 

refers:

https://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html

https://www.cnblogs.com/owenChen/archive/2013/02/18/2915521.html

https://www.cnblogs.com/yuanjun1/p/4001953.html

https://www.cnblogs.com/yaoyinglong/p/5738979.html

https://blog.csdn.net/lihongxun945/article/details/12029395

http://www.360doc.com/content/13/1128/09/10504424_332741972.shtml

https://www.cnblogs.com/aaronjs/p/3348569.html

相關文章
相關標籤/搜索