首先:JSON和JSONP是不一样的概念。
JSON是一种数据交换格式,而JSONP是非正式传输协议。
该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据。
其实现细节是使用 Script标签携带一个Callback函数,动态的向服务端请求数据。
如:
<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>会被移除。
早期版本中叫delegate, 后来有过live函数,再后来统一用on。下面的方法等效
// 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原理需要首先了解二个概念:事件捕获和事件冒泡

源码片段如下:
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
原文:https://www.cnblogs.com/full-stack-engineer/p/8988362.html