首先: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, 後來有過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
源碼片斷以下: 瀏覽器
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 ); } }
... } ... }
如下是相似綁定的對比(後期綁定:元素已經加載後,進行事件的綁定。前期綁定:元素還沒有存在,爲動態元素添加事件):
Jquery使用事件冒泡(作了兼容性處理),經過addEventListener到父元素進行事件監聽,經過e.target判斷觸發元素。
做用: Jquery.data() 方法向被選元素附加數據,或者從被選元素獲取數據。
Jquery在原型和構造上均有data方法,jQuery.extend 與 jQuery.fn.extend 的區別在於:
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: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對象
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;
...
}
}
獲取事件句柄,經過apply方法調用定義的回調函數。並執行默認行爲。
相似於trigger,可是不會觸發元素的默認行爲,例如a標籤的跳轉行爲,submit的提交行爲等,且不會在DOM樹中冒泡,所以事件不會傳遞給它的任何祖輩元素
源碼片斷以下:
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動畫的瀏覽器上實現動畫效果。
源碼片斷以下:
// 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採用試圖滾動頁面,能滾動了就證實加載好了並進行回調。
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 來規範化異步操做,讓異步操做的流程控制更加容易。
核心:按需加載
插件: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