JavaScript的Deferred是比较高大上的东西,  主要的应用还是主ajax的应用,  因为JS和nodeJS这几年的普及,  前端的代码越来越多,  各种回调套回调再套回调实在太让人崩溃, 所以就从后端拖了一个延迟对象这货, 用来解决回调地狱这个问题 。

   我们使用ajax的时候多数都是为ajax添加回调 ,然后异步向服务器发送请求, 比如如下原生的XHR代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
填坑必备
</title>
</head>
<body>
<div id="results">
data
</div>
<script>
var results = document.getElementById('results');
var r = new XMLHttpRequest();
r.open("GET", "http://www.filltext.com?rows=10&f={firstName}", true);
r.onreadystatechange = function () {
if (r.readyState != 4 || r.status != 200) return;
var data = JSON.parse(r.responseText);
for (i=0;i<data.length;i++){
results.innerHTML += '<li>'+data[i].f+'</li>'
};
};
r.send();
</script>
</body>
</html>

  因为jQ1.5以后版本的ajax的实例对象继承了延迟对象, 我们可以使用ajax实例的then或者done以及fail等等方法 ,所以上面的代码可以改写为:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
填坑必备
</title>
</head>
  //bootcdn这个cdn满好用的, 上面好多库哇, 推荐一下;
<script src="http://cdn.bootcss.com/jquery/2.1.3/jquery.min.js"></script>
<body>
<div id="results">
data
</div>
<script>
                                      //then : $.get, $.post, $.ajax返回的对象是延迟对象(deferred);
$.get("http://www.filltext.com?rows=10&f={firstName}").then(function(data){
          console.log(data);
for (i=0;i<data.length;i++){
$("#results").html(function(){
return $.map(data,function( obj ) {
return obj.f
}).join(" || ")
})
};
});
</script>
</body>
</html>

  下划线的这个是网上抄的,不想看可以略过:异步模式在web编程中变得越来越重要,对于web主流语言Javscript来说,这种模式实现起来不是很利索,为此,许多Javascript库(比如 jQuery和Dojo)添加了一种称为promise的抽象(有时也称之为deferred)。通过这些库,开发人员能够在实际编程中使用 promise模式。

  先说下延迟对象的三种状态, 当一个延迟对象被初始化那么该对象默认为peding状态

    1:pending等待状态

     2:fulfilled执行完成状态

     3:rejected拒绝状态;

  延迟对象的两个主要方法:

    1:add 这个方法是添加成功回调

    2:fail 这个方法是添加拒绝回调

  延迟对象比较高级的方法:

    1:then方法; 该方法返回一个包裹了旧延迟对象新延迟对象

    2:promise方法;这个对象返回的是阉割后的Defered(延迟对象),主要作用是保护原来延迟对象;

    3:when这个方法不是在延迟对象的实例上, (根据库的不同, when这个方法在不同的地方,比如jQ的when方法是$.when,别的库( •̀ ω •́ ) 也说不准, 反正when的源代码是在Deferred附近), 但是和延迟对象息息相关, 因为这个方法返回的也是一个延迟对象, 顾名思义when的作用就是:when你传的几个延迟对象全部resolve以后, when的返回实例会resolve....懂得自然懂, 不急;

  下面这张图是jQ这个Deferred实例对象方法, 提供参考:

  以下的JS代码是《司徒框架设计》里面介绍的延迟对象mochikit, 可以自己在控制台跟踪一下就知道执行的流程:
mochikit延迟对象源代码如下, 这个延迟对象很好理解;GitHub的地址是: https://github.com/mochi/mochikit/

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
</head>
<body>
<script>
/** @id MochiKit.Async.Deferred */
var MochiKitDeferred = function (/* optional */ canceller) {
this.chain = [];
this.id = this._nextId();
this.fired = -1;
this.paused = 0;
this.results = [null, null];
this.canceller = canceller;
this.silentlyCancelled = false;
this.chained = false;
this.finalized = false;
this.GenericError = function(msg){
return new Error("GenericError"+msg);
};
this.CancelledError = function(msg) {
return new Error("CancelledError"+msg);
};
}; MochiKitDeferred.prototype = {
/** @id MochiKit.Async.Deferred.prototype.repr */
repr: function () {
return 'Deferred(' + this.id + ', ' + this.state() + ')';
}, toString: "", _nextId: function() {
//return setTimeout("",0),中间要有一个空格, 要么不行;
return setTimeout(" ",0);
}, /** @id MochiKit.Async.Deferred.prototype.state */
state: function () {
if (this.fired == -1) {
return 'unfired';
} else if (this.fired === 0) {
return 'success';
} else {
return 'error';
}
},
/** @id MochiKit.Async.Deferred.prototype.cancel */
cancel: function (e) {
var self = this;
if (this.fired == -1) {
if (this.canceller) {
this.canceller(this);
} else {
this.silentlyCancelled = true;
}
if (this.fired == -1) {
if (typeof(e) === 'string') {
e = new self.GenericError(e);
} else if (!(e instanceof Error)) {
e = new self.CancelledError(this);
}
this.errback(e);
}
} else if ((this.fired === 0) && (this.results[0] instanceof self.Deferred)) {
this.results[0].cancel(e);
}
}, _resback: function (res) {
/*** The primitive that means either callback or errback ***/
this.fired = ((res instanceof Error) ? 1 : 0);
this.results[this.fired] = res;
if (this.paused === 0) {
this._fire();
}
}, _check: function () {
if (this.fired != -1) {
if (!this.silentlyCancelled) {
throw new MochiKit.Async.AlreadyCalledError(this);
}
this.silentlyCancelled = false;
return;
}
}, /** @id MochiKit.Async.Deferred.prototype.callback */
callback: function (res) {
this._check();
if (res instanceof MochiKit.Async.Deferred) {
throw new Error("Deferred instances can only be chained if they are the result of a callback");
}
this._resback(res);
}, /** @id MochiKit.Async.Deferred.prototype.errback */
errback: function (res) {
this._check();
var self = MochiKit.Async;
if (res instanceof self.Deferred) {
throw new Error("Deferred instances can only be chained if they are the result of a callback");
}
if (!(res instanceof Error)) {
res = new self.GenericError(res);
}
this._resback(res);
}, /** @id MochiKit.Async.Deferred.prototype.addBoth */
addBoth: function (fn) {
return this.addCallbacks(fn, fn);
}, /** @id MochiKit.Async.Deferred.prototype.addCallback */
addCallback: function (fn) {
if (arguments.length > 1) {
fn = MochiKit.Base.partial.apply(null, arguments);
}
return this.addCallbacks(fn, null);
}, /** @id MochiKit.Async.Deferred.prototype.addErrback */
addErrback: function (fn) {
if (arguments.length > 1) {
fn = MochiKit.Base.partial.apply(null, arguments);
}
return this.addCallbacks(null, fn);
}, /** @id MochiKit.Async.Deferred.prototype.addCallbacks */
addCallbacks: function (cb, eb) {
if (this.chained) {
throw new Error("Chained Deferreds can not be re-used");
}
if (this.finalized) {
throw new Error("Finalized Deferreds can not be re-used");
}
this.chain.push([cb, eb]); //已经触发了, 让他emitDirect;
if (this.fired >= 0) {
this._fire();
}
return this;
}, _fire: function () {
/*** Used internally to exhaust the callback sequence when a result
is available. ***/
var chain = this.chain;
var fired = this.fired;
var res = this.results[fired];
var self = this;
var cb = null;
while (chain.length > 0 && this.paused === 0) {
// Array
var pair = chain.shift();
var f = pair[fired];
if (f === null) {
continue;
};
try {
res = f(res);
fired = ((res instanceof Error) ? 1 : 0);
if (res instanceof MochiKitDeferred) {
//new如果返回的是延迟对象, 那么this的.paused就被卡住了;
cb = function (res) {
self.paused--;
self._resback(res);
};
/*
*/
this.paused++;
};
} catch (err) {
fired = 1;
if (!(err instanceof Error)) {
err = new MochiKitDeferred.GenericError(err);
}
res = err;
};
};
this.fired = fired;
this.results[fired] = res;
if (this.chain.length == 0 && this.paused === 0 && this._finalizer) {
this.finalized = true;
this._finalizer(res);
}
if (cb && this.paused) {
// this is for "tail recursion" in case the dependent deferred
// is already fired
res.addBoth(cb);
res.chained = true;
}
}
}; //这个延迟对象最常用方式是这样:
var df = new MochiKitDeferred();
df.addBoth(function(){
console.log(1);
}).addBoth(function(){
console.log(2)
})
df._resback(); // 控制他打出 ==>1 \n\r 2 \n\r; //这个延迟对象最常用方式是这样;
//当然, 你可以把上面一个函数的返回值作为下一个函数的参数, 如下:
var df = new MochiKitDeferred();
df.addBoth(function(){
return 0
}).addBoth(function(arg){
console.log(arg);
return 1;
}).addBoth(function(arg){
console.log(arg);
return 2;
}).addBoth(function(arg){
console.log(arg);
})
df._resback(); // 控制他打出 ==>1 \n\r 2 \n\r; </script>
</body>
</html>

  博客园上博友教你写一个比较简单的延迟对象, 地址是: http://www.cnblogs.com/ygm125/p/3735677.html

  是代码量比较少的, 也好理解, 实在不懂就开控制器一步一步跟踪, 多看几遍, 不懂都说不过去:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
</head>
<body>
<script> (function(window,undefined){ var PENDING = undefined, FULFILLED = 1, REJECTED = 2; var isFunction = function(obj){
return 'function' === typeof obj;
}
var isArray = function(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
}
var isThenable = function(obj){
return obj && typeof obj['then'] == 'function';
} var transition = function(status,value){
var promise = this;
if(promise._status !== PENDING) return;
// 所以的执行都是异步调用,保证then是先执行的
setTimeout(function(){
promise._status = status;
publish.call(promise,value);
});
}
var publish = function(val){
var promise = this,
fn,
st = promise._status === FULFILLED,
queue = promise[st ? '_resolves' : '_rejects']; while(fn = queue.shift()) {
val = fn.call(promise, val) || val;
}
promise[st ? '_value' : '_reason'] = val;
promise['_resolves'] = promise['_rejects'] = undefined;
} var Promise = function(resolver){
if (!isFunction(resolver))
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
if(!(this instanceof Promise)) return new Promise(resolver); var promise = this;
promise._value;
promise._reason;
promise._status = PENDING;
promise._resolves = [];
promise._rejects = []; var resolve = function(value){
transition.apply(promise,[FULFILLED].concat([value]));
}
var reject = function(reason){
transition.apply(promise,[REJECTED].concat([reason]));
} resolver(resolve,reject);
} Promise.prototype.then = function(onFulfilled,onRejected){
var promise = this;
// 每次返回一个promise,保证是可thenable的
return Promise(function(resolve,reject){
function callback(value){
var ret = isFunction(onFulfilled) && onFulfilled(value) || value;
if(isThenable(ret)){
ret.then(function(value){
resolve(value);
},function(reason){
reject(reason);
});
}else{
resolve(ret);
}
}
function errback(reason){
reason = isFunction(onRejected) && onRejected(reason) || reason;
reject(reason);
}
if(promise._status === PENDING){
promise._resolves.push(callback);
promise._rejects.push(errback);
}else if(promise._status === FULFILLED){ // 状态改变后的then操作,立刻执行
callback(promise._value);
}else if(promise._status === REJECTED){
errback(promise._reason);
}
});
} Promise.prototype.catch = function(onRejected){
return this.then(undefined, onRejected)
} Promise.prototype.delay = function(ms){
return this.then(function(val){
return Promise.delay(ms,val);
})
} Promise.delay = function(ms,val){
return Promise(function(resolve,reject){
setTimeout(function(){
resolve(val);
},ms);
})
} Promise.resolve = function(arg){
return Promise(function(resolve,reject){
resolve(arg)
})
} Promise.reject = function(arg){
return Promise(function(resolve,reject){
reject(arg)
})
} Promise.all = function(promises){
if (!isArray(promises)) {
throw new TypeError('You must pass an array to all.');
}
return Promise(function(resolve,reject){
var i = 0,
result = [],
len = promises.length; function resolver(index) {
return function(value) {
resolveAll(index, value);
};
} function rejecter(reason){
reject(reason);
} function resolveAll(index,value){
result[index] = value;
if(index == len - 1){
resolve(result);
}
} for (; i < len; i++) {
promises[i].then(resolver(i),rejecter);
}
});
} Promise.race = function(promises){
if (!isArray(promises)) {
throw new TypeError('You must pass an array to race.');
}
return Promise(function(resolve,reject){
var i = 0,
len = promises.length; function resolver(value) {
resolve(value);
} function rejecter(reason){
reject(reason);
} for (; i < len; i++) {
promises[i].then(resolver,rejecter);
}
});
} window.Promise = Promise; })(window); //常见的使用方式如下:
var getData100 = function(){
return Promise(function(resolve,reject){
setTimeout(function(){
resolve('100ms');
},100);
});
} var getData200 = function(){
return Promise(function(resolve,reject){
setTimeout(function(){
resolve('200ms');
},200);
});
} getData100().then(function(data){
console.log(data); // 100ms
return getData200();
}).then(function(data){
console.log(data); // 200ms
return data + data;
}).then(function(data){
console.log(data) // 200ms200ms
});
</script>
</body>
</html>

  

  公司这边的老段写的Deferred, 是从TypeScript编译成js的, 因为这个东西比较简单, 应该不算泄露公司机密哇, 代码的最后有几个使用的实例, 你点击运行即可查看, 有兴趣自己写一个延迟对象, 印象会更加深刻:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
</head>
<body>
<script> //d为目标对象, b为一个函数对象;
var __extends = this.__extends || function (d, b) {
//继承了静态属性
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
//继承了原型
__.prototype = b.prototype;
d.prototype = new __();
}; //Promise这个构造器, Deferred继承Promise;
var Promise = (function () {
function Promise() {
}
/**
* onDone/onFail 应该返回值(或抛出异常),即不应返回 undefined,忘记返回值通常是 Bug,因此会在控制台给出警告。
* 如果确实不需要返回值,可返回 null。
*/
Promise.prototype.then = function (onDone, onFail) {
return null;
};
Object.defineProperty(Promise.prototype, "status", {
get: function () {
return 0;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Promise.prototype, "result", {
get: function () {
return undefined;
},
enumerable: true,
configurable: true
});
Promise.prototype.done = function (onDone) {
return this;
};
Promise.prototype.fail = function (onFail) {
return this;
};
Promise.prototype.progress = function (onProgress) {
return this;
}; Promise.when = function (promises) {
var allDone = new Deferred();
if (!promises.length) {
allDone.resolve([]);
return allDone;
}
var resolved = 0;
for (var i = 0; i < promises.length; i++) {
promises[i].done(function (v) {
++resolved;
if (resolved === promises.length && allDone.status === Promise.UNFULFILLED) {
var results = promises.map(function (p) {
return p.result;
});
allDone.resolve(results);
}
}).fail(function (e) {
if (allDone.status === Promise.UNFULFILLED)
allDone.reject(e); //TODO 此处i是无用的,怎么指示是哪一个promise的信息?
}).progress(function (v) {
if (allDone.status === Promise.UNFULFILLED) {
allDone.notify(v); //TODO 此处i是无用的,怎么指示是哪一个promise的信息?
}
});
}
return allDone;
}; Promise.UNFULFILLED = 0;
Promise.RESOLVED = 1;
Promise.REJECTED = 2;
return Promise;
})(); var Deferred = (function (_super) {
//继承原型
__extends(Deferred, _super);
function Deferred() {
//继承
_super.call(this);
//成功的列表;
this._onDones = null;
//失败的列表;
this._onFails = null;
//进度的回调列表;
this._onProgresses = null;
// 0 : 为解决, 1 : 已解决, 2 : 被拒绝了;
this._status = Promise.UNFULFILLED;
this._result = undefined;
if (Deferred._DEBUG) {
try {
throw new Error('Deferred constructor calling stack');
} catch (e) {
this._stack = e;
};
};
}; //直接通过访问_status也行;
Object.defineProperty(Deferred.prototype, "status", {
get: function () {
return this._status;
},
enumerable: true,
configurable: true
}); //直接访问实例的_result也行;
Object.defineProperty(Deferred.prototype, "result", {
get: function () {
return this._result;
},
enumerable: true,
configurable: true
}); //把callback的成功列表全部压栈;
Deferred.prototype.done = function (onDone) {
if (this._status == Promise.UNFULFILLED) {
this._onDones = this._onDones || [];
this._onDones.push(onDone);
//如果已经成功直接触发成功回调, (这里要注意有种情况是“已经失败”的姿态, 这个成功回调并不会入栈或者触发);
} else if (this._status == Promise.RESOLVED)
this._emitEventDirectly(onDone);
return this;
}; //把callback的失败列表全部压栈;
Deferred.prototype.fail = function (onFail) {
if (this._status == Promise.UNFULFILLED) {
this._onFails = this._onFails || [];
this._onFails.push(onFail);
//如果已经失败直接触发失败回调;
} else if (this._status == Promise.REJECTED)
this._emitEventDirectly(onFail);
return this;
}; Deferred.prototype.progress = function (onProgress) {
if (this._status == Promise.UNFULFILLED) {
this._onProgresses = this._onProgresses || [];
this._onProgresses.push(onProgress);
}
return this;
}; //then这个很重要, 他会重新返回包装后的延迟对象, 也是延迟对象里面比较复杂的东西;
//功过then可以实现链式调用, 实例如下:
/*
var df = new Deferred();
df.then(function() {
return 1
}).then(function(arg) {
console.log(arg);
return 2;
}).then(function(arg){
console.log(arg)
});
df.resolve();
*/
Deferred.prototype.then = function (onDone, onFail) {
var _this = this;
var def = new Deferred();
var result; //then返回的是新的延迟对象
//done是为当前这个延迟对象添加延迟对象;
this.done(function (data) {
// 这个done很重要, 有三个判断;
// 如果有没有onDone就直接为当前的resolve; 一个旧的derffer被resolve了那么新的deferred也resovle, resolve的参数为旧deferred的参数:实例如下
/*
var df = new Deferred();
df.then().done(function(arg){
console.log(arg);
});
df.resolve("1");
*/ // 如果有onDone, onDone的返回是非Deferred对象,通过resolve(返回值)闭包内的Deferred对象, 实例如下:
/*
var df = new Deferred();
df.then(function() {return 2}).done(function(arg){
console.log(arg);
});
df.resolve();
*/ // 如果有onDone, 而且onDone返回对象是Promise的实例, 那么为返回的这个promise添加一个onDone, 这个onDone添加闭包内部的promise对象的resolve, 实例如下:
/*
var df = new Deferred();
df.then(function() {
var closureDf = new Deferred();
setTimeout(function(){
closureDf.resolve("haha")
},4000);
return closureDf.promise();
}).done(function(arg){
console.log(arg);
});
df.resolve(); */
if (onDone) {
try {
result = onDone(data);
//主要是起到提示的作用;
_this._warnReturnValue(result);
if (result instanceof Promise) {
//result又是一个延迟对象的话, 当result发生resolve的时候,def也reslove
//result.done(def.resolve.bind(this)).fail(def.reject.bind(this)).progress(def.notify.bind(this));
//result.done(function(arg){ def.resolve(arg) }).fail(function(arg){ def.reject(arg) })
def._bindTo(result);
//
return result;
} else
//最好不要延迟对象套延迟对象, 会晕;
def.resolve(result);
} catch (err) {
def.reject(err);
}
} else
def.resolve(data);
});
this.fail(function (err) {
if (onFail) {
try {
result = onFail(err);
_this._warnReturnValue(result);
if (result instanceof Promise) {
def._bindTo(result);
return result;
} else {
def.resolve(result);
}
} catch (err2) {
def.reject(err2);
}
} else
def.reject(err);
}); return def;
}; Deferred.prototype.resolve = function (data) {
if (typeof data === 'undefined')
console.warn('>>>> Deferred.resolve() received undefined, likely a bug');
return this._emitEvent(data, Promise.RESOLVED);
}; Deferred.prototype.reject = function (err) {
if (Deferred._DEBUG) {
try {
throw new Error('Deferred.reject calling stack');
} catch (e) {
logw('rejected: Defered.constructor stack:\n' + (this._stack['stack'] || this._stack) + '\nrejected: Defered.rejected stack:\n' + (e['stack'] || e) + '\nrejected: reason stack:\n' + (err['stack'] || err));
}
}
return this._emitEvent(err, Promise.REJECTED);
}; Deferred.prototype.notify = function (data) {
return this._emitEvent(data);
}; //这个是触发事件的装饰者, 你要触发失败回调, 成功回调, 进度回调都需要走这边, 只是穿进来的姿态不一样而已;
Deferred.prototype._emitEvent = function (data, status) {
if (this._status != Promise.UNFULFILLED) {
throw Error('fulfilled');
} var callbacks;
//处理事件列表;
if (status === Promise.RESOLVED)
callbacks = this._onDones;
else if (status === Promise.REJECTED)
callbacks = this._onFails;
else
callbacks = this._onProgresses; //没有status是onProgress的情况;
if (status) {
this._status = status;
this._result = data;
this._onDones = this._onFails = this._onProgresses = null;
}; if (callbacks) {
for (var i = 0; i < callbacks.length; i++) {
try {
//这个是执行回调列表, 是线性的;
callbacks[i](data);
} catch (e) {
this._log(e);
}
}
}
return this;
}; Deferred.prototype._bindTo = function (p) {
p.done(this.resolve.bind(this)).fail(this.reject.bind(this)).progress(this.notify.bind(this));
}; Deferred.prototype._emitEventDirectly = function (callback) {
var _this = this;
if (!callback)
return;
setTimeout(function () {
try {
callback(_this._result);
} catch (e) {
_this._log(e);
}
}, 0);
}; Deferred.prototype._log = function (err) {
console.warn(err.stack || err);
}; Deferred.prototype._warnReturnValue = function (value) {
if (typeof value === 'undefined')
console.warn('>>>> Promise.then(): onDone/onFail returns undefined, likely a bug');
else if (value && !(value instanceof Promise) && typeof value.then === 'function')
console.warn('>>>> Promise.then(): onDone/onFail returns a promise-like object, likely a bug. Consider Promise.wrap().');
};
Deferred._DEBUG = false;
return Deferred;
})(Promise); //使用方法:
var df = new Deferred();
df.then(function() {
return 1
}).then(function(arg) {
console.log(arg);
return 2;
}).then(function(arg){
console.log(arg)
});
df.resolve(); //单纯的Deferred相对于一个callbacks, 使用then方法就变成了链式调用(个人理解);
var df = new Deferred();
df.then().done(function(arg){
console.log(arg);
});
df.resolve("1"); //欢迎拍砖;
var df = new Deferred();
df.then(function() {return 2}).done(function(arg){
console.log(arg);
});
df.resolve();
</script>
</body>
</html>

  jQ1.7的延迟对象, 代码量比较少, 依赖callbacks,不太好懂, 慢慢看,参考jQ的延迟对象分析:http://www.cnblogs.com/snandy/archive/2012/12/19/2812935.html

 

   要先弄懂callbacks这个方法, 才能在弄懂Deferred,  when也只是一个Deferred的包装。 建议先看1.5版本的Deferred, 弄懂了再看1.7的Deferred, 下面的Deferred被我单独裁出来了,可以单独运行, 里面的注释是博客园的好像是aaron写的代码解析, 辅助大家看一下:

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script>
//jQ部分的延迟对象截取;
jQuery = $ = {};
jQuery.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false; // Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
} // Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
} // extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
} for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ]; // Prevent never-ending loop
if ( target === copy ) {
continue;
} // Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : []; } else {
clone = src && jQuery.isPlainObject(src) ? src : {};
} // Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
} // Return the modified object
return target;
}; var optionsCache = {};
var core_rspace = /\s+/;
var core_toString = Object.prototype.toString;
var class2type = {};
jQuery.each = function( obj, callback, args ) {
var name,
i = 0,
length = obj.length,
isObj = length === undefined || jQuery.isFunction( obj ); if ( args ) {
if ( isObj ) {
for ( name in obj ) {
if ( callback.apply( obj[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( obj[ i++ ], args ) === false ) {
break;
}
}
} // A special, fast, case for the most common use of each
} else {
if ( isObj ) {
for ( name in obj ) {
if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
break;
}
}
}
};
return obj;
};
$.isFunction = function( obj ) {
return jQuery.type(obj) === "function";
}
$.type = function( obj ) {
return obj == null ?
String( obj ) :
class2type[ core_toString.call(obj) ] || "object";
};
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
// Convert String-formatted options into Object-formatted ones and store in cache
function createOptions( options ) {
var object = optionsCache[ options ] = {};
jQuery.each( options.split( core_rspace ), function( _, flag ) {
object[ flag ] = true;
});
return object;
};
//$.Callbacks( 'once memory unique stopOnFalse' );
jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) :
jQuery.extend( {}, options ); var // Last fire value (for non-forgettable lists)
memory,
// Flag to know if list was already fired
fired,
// Flag to know if list is currently firing
firing,
// First callback to fire (used internally by add and fireWith)
firingStart,
// End of the loop when firing
firingLength,
// Index of currently firing callback (modified by remove if needed)
firingIndex,
// Actual callback list
list = [],
// Stack of fire calls for repeatable lists
stack = !options.once && [],
// Fire callbacks
fire = function( data ) {
//如果有memory我们会把传进来的参数保存;
memory = options.memory && data;
//触发的标志;
fired = true;
//如果有memory的callback对象执行过了, 会有firingStart;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
//callback已经触发过后的标志;
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
//return false的时候就不走了
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
memory = false; // To prevent further calls using add
break;
}
};
firing = false;
if ( list ) {
if ( stack ) {
if ( stack.length ) {
fire( stack.shift() );
}
} else if ( memory ) {
list = [];
} else {
self.disable();
}
}
},
//通过闭包, 保存局部变量, 返回self;
// Actual Callbacks object
self = {
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
// First, we save the current length
var start = list.length; // 如果传进来的是[fn, fn1, fn2 , [fn3, fn4, fn5, fn6]]会把数组扁平化哦
// Array.prototype.concat.apply([],[1,2,3,[4,5]]); 你懂得....;
(function add( args ) {
jQuery.each( args, function( _, arg ) {
//
if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) {
list.push( arg );
} else if ( arg && arg.length ) {
// Inspect recursively
add( arg );
}
});
})( arguments );
// Do we need to add the callbacks to the
// current firing batch?
// 对定制选项的额外处理;
if ( firing ) {
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away
} else if ( memory ) {
firingStart = start;
fire( memory );
}
}
return this;
},
// Remove a callback from the list
remove: function() {
//没list就不玩了;
if ( list ) {
jQuery.each( arguments, function( _, arg ) {
var index;
while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
// 对定制选项的额外处理;
if ( firing ) {
if ( index <= firingLength ) {
firingLength--;
}
if ( index <= firingIndex ) {
firingIndex--;
}
}
}
});
}
return this;
},
// Control if a given callback is in the list
has: function( fn ) {
return jQuery.inArray( fn, list ) > -1;
},
// Remove all callbacks from the list
empty: function() {
list = [];
return this;
},
// Have the list do nothing anymore
disable: function() {
list = stack = memory = undefined;
return this;
},
// Is it disabled?
disabled: function() {
return !list;
},
// Lock the list in its current state
lock: function() {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
},
// Is it locked?
locked: function() {
return !stack;
},
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
if ( list && ( !fired || stack ) ) {
if ( firing ) {
stack.push( args );
} else {
fire( args );
}
}
return this;
},
// Call all the callbacks with the given arguments
fire: function() {
self.fireWith( this, arguments );
return this;
},
// To know if the callbacks have already been called at least once
fired: function() {
return !!fired;
}
}; return self;
}; //接着, 来参考一下jQ的延迟对象 , 原文地址在:http://www.cnblogs.com/lovesueee/archive/2012/10/18/2730287.html;
jQuery.extend({ Deferred: function( func ) {
// 数据元组集
// 每个元组分别包含一些与当前deferred相关的信息:
// 分别是:触发回调函数列表执行(函数名),添加回调函数(函数名),回调函数列表(jQuery.Callbacks对象),deferred最终状态(第三组数据除外)
// 总体而言,三个元组会有对应的三个callbacklist对应于doneList, failList, processList
// 对于jQuery.Callbacks对象,可以看之前的文章http://www.cnblogs.com/lovesueee/archive/2012/10/18/2729829.html
var tuples = [
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
// deferred的状态,分为三种:pending(初始状态), resolved(解决状态), rejected(拒绝状态)
state = "pending",
// promise对象,主要有两点作用:
// 1. 在初始化deferred对象时,promise对象里的方法都会被extend到deferred中去
// 2. 那么,生成的deferred对象里必然引用了promise对象的promise方法,所以当调用deferred.promise()时,
// deferred对象会通过闭包返回promise对象,这就是所谓的受限制的deferred对象(用deferred2表示),因为相比之前,
// 返回的deferred2不在拥有resolve(With), reject(With), notify(With)这些能改变deferred对象状态并且执行callbacklist的方法了
promise = { // 返回闭包里的内部state(外部只读)
state: function() {
return state;
}, // 同时在doneList和failList的list里添加回调函数(引用)
// 那么不论deferred最终状态是resolved还是rejected, 回调函数都会被执行,这就是所谓的always
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
}, // jQuery.then()会创建一个新的受限制的deferred对象
// 有点复杂,下面我有画一个图帮忙理解
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
// 创建新的受限制的deferred对象(称作newDeferrred),并返回
// 利用返回的deferred对象就可以做很多事了,你懂的
return jQuery.Deferred(function( newDefer ) {
/*
var tuples = [
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
]
*/
jQuery.each( tuples, function( i, tuple ) {
var action = tuple[ 0 ],
fn = fns[ i ];
// >>>> 很重要的一点就是:then这个方法是新建一个deferred,然后把当前deferred的done, fail progress三个依次添加新deferred, 并把这个deferred返回; <<<< // deferred[ done | fail | progress ] for forwarding actions to newDefer
// 分别为deferred的三个callbacklist添加回调函数,根据fn的是否是函数,分为两种情况:
// 1.不是函数的情况(如值为undefined或者null等),直接链接到newDeferred的resolve(reject,notify)方法,也就是说
// newDeferrred的执行依赖外层的调用者deferred的状态或者说是执行动作(resolve还是reject或者是notify)
// 此时deferred.then()相当于将自己的callbacklist和newDeferred的callbacklist连接起来了,故可以在newDeferred
// 中大做文章
// 2.是函数的情况,根据返回值(称作returnReferred)是否是deferred对象,又可以分为两种情况:
// 2.1 返回值是deferred对象,那么在returnReferred对象的三个回调函数列表中添加newDeferred的resolve(reject,notify)方法
// 也就是说newDeferrred的执行依赖returnDeferred的状态
// 2.2 返回值不是deferred对象,那么将返回值returned作为newDeferred的参数并将从外层deferred那边的上下文环境作为newDeferred
// 的执行上下文,然后执行对应的回调函数列表,此时newDeferrred的执行依赖外层的调用者deferred的状态 //deferred.done(fn), deferred.fail(fn), deferred.progress(fn);
deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
//传进来的是函数的情况下, 函数可能不返回, 也可能返回一个延迟对象;;
function() {
//这行传进来的参数, 利用闭包, fn是这个闭包的变量;
var returned = fn.apply( this, arguments );
//又返回了一个延迟对象的话, 我们再把这个新的延迟对象的resolve和reject和notify放到这个deferred;
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
//这个函数返回的不是延迟对象, 把这个fn的返回值作为参数触发newDefer;
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
}
} :
newDefer[ action ]
);
});
fns = null;
}).promise();
}, promise: function( obj ) {
return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise;
}
},
// 实际返回的deferred对象
deferred = {}; // Keep pipe for back-compat
// pipe和then引用同一个函数,所以功能是一样的
// 只不过通常的用法是:会用pipe进行filter操作
promise.pipe = promise.then; // Add list-specific methods
// 通过上面定义的数据元组集来扩展一些方法
jQuery.each( tuples, function( i, tuple ) {
//就是callback了;
var list = tuple[ 2 ],
//resolved, rejected
stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add
// 给上面的promise对象添加done,fail,process方法
// 这三个方法分别引用三个不同jQuery.Callbacks对象的add方法(不是同一个引用),
// 那么这三个方法的用途就是向各自的回调函数列表list(各自闭包中)中添加回调函数,互不干扰
promise[ tuple[1] ] = list.add; // Handle state
// 通过stateString有值这个条件,预先向doneList,failList中的list添加三个回调函数
// doneList : [changeState, failList.disable, processList.lock]
// failList : [changeState, doneList.disable, processList.lock]
// changeState 指的是下面首先添加的一个改变deferred对象的匿名函数
// 可以看的出: 不论deferred对象最终是resolve(还是reject),在首先改变对象状态之后,都会disable另一个函数列表failList(或者doneList)
// 然后lock processList保持其状态,最后执行剩下的之前done(或者fail)进来的回调函数
// 当然了,上述情况processList除外
if ( stateString ) {
// 一旦触发就会把这个闭包的姿态字符串保存的state里面去;
list.add(function() {
// state = [ resolved | rejected ]
state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
} // deferred[ resolve | reject | notify ] = list.fire
// 给deferred对象添加resolve(With), reject(With), notify(With)方法
// 这三个方法分别引用三个不同jQuery.Callbacks对象的fire方法;
deferred[ tuple[0] ] = list.fire;
deferred[ tuple[0] + "With" ] = list.fireWith;
}); // jQuery.extend( deferred, promise );
// 将上面的promise对象extend进deferred中
promise.promise( deferred ); // Call given func if any
// 如果调用jQuery.Deferred(func)指定了参数,那么调用func并设置func的上下文和参数均为deferred
// 在jQuery.then()中有用到这一点
if ( func ) {
func.call( deferred, deferred );
} // All done!
// 返回最终的deferred对象
return deferred;
}, //suborinate:部属;部下,下级的意思,
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
// 首先将arguments伪数组转换为真正的数组
resolveValues = core_slice.call( arguments ),
length = resolveValues.length, // the count of uncompleted subordinates
// jQuery.isFunction( subordinate.promise )用来判断subordinate是否是deferred对象
// 1. 在参数个数等于1的情况下:
// 1.1 如果参数是deferred对象,那么remaining = length, 这是remaining就是1嘛
// 1.2 否则remaining为0
// 2. 在参数不等于1(即等于0或者大于1)的情况:remaining = length
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
// 到这里就可以知道:如果参数个数仅为1个,并且是deferred对象,那么就无需再生成deferred对象
deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
// 这里返回一个函数作为一个callback完全是为了创建一个闭包,主要是为了保持i的值
return function( value ) {
// 保存各个deferred执行的上下文,也就是说之后whenDeferred的回调函数的上下文就是一个数组
contexts[ i ] = this;
// 保存各个deferred执行时的参数,之后传递给whenDeferred的回调函数
// 此时values的值有原先的jQuery.when()传进来的参数变为各个deferred执行回调时的参数了,也就是说覆盖了
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
if( values === progressValues ) {
deferred.notifyWith( contexts, values );
//所有的defer都执行了以后remaining就等于0了;
} else if ( !( --remaining ) ) {
// 时机成熟,即所有延迟都resolve,执行whenDeferred的回调函数
deferred.resolveWith( contexts, values );
}
};
}, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved
// 如果参数个数大于1,那么就是说有可能存在多个deferred对象
// 这时需要一些条件判断以保证是所有的deferred对象都resolve了,再执行whenDeferred的resolve
// 或者当有一个deferred对象reject了,whenDeferred的reject
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
// 如果是deferred对象, 为每一个promise添加update,失败就执行返回deferred的fail列表;
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
// 给每个参数(deferred对象)添加最后的回调,用来检查此时的状态 resolveValues[ i ].promise()
// 用于当每一个deferred对象resolve回来,用updateFunc返回的函数检查此时其他deferred对象的状态(即此时remaining是否等于0了)
//updateFunc是一个闭包, 他把i传进去了, 只有then().done()或者then().promise()有返回值, promise(),或者是done是没有返回值的;
.done( updateFunc( i, resolveContexts, resolveValues ) )
// 如果有一个deferred对象reject,whenDeferred将执行reject
.fail( deferred.reject )
//updateFunc又是一个闭包, ;
.progress( updateFunc( i, progressContexts, progressValues ) );
// 如果不是deferred对象,直接--remaining,视为resolve
} else {
--remaining;
};
};
}; // if we're not waiting on anything, resolve the master
// 如果此时remaining就等与0了,表示没有什么延迟需要等待,那么立即之行whenDeferred的resolveWith
// 此时resolveContexts为undefined, 这就意味这上下文将为全局的window
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
} // 返回promise对象;
return deferred.promise();
}
}); var df = $.Deferred();
df.done(function(arg){
console.log(arg);
console.log(1)
})
df.done(function(arg){
console.log(arg);
console.log(2)
});
df.resolve("Deffffffffffrrrrred"); //延迟对象pipe的使用, pipe和then是一样的, 指向同一个函数;
var df = $.Deferred();
df.pipe(function() {
var closureDf = $.Deferred();
setTimeout(function(){
closureDf.resolve("haha")
},4000);
console.log(closureDf);
return closureDf;
}).done(function(arg){alert(1)
console.log(arg);
});
df.resolve(); </script>
</body>
</html>

  ES6原生的好像支持PROMISE么么哒,O(∩_∩)O哈哈~;

  
参考链接:
  用法:
    阮一峰的jQuery.Deferred对象: http://javascript.ruanyifeng.com/jquery/deferred.html

  Aaron:

    Aaron深入分析延迟对象:http://www.cnblogs.com/aaronjs/p/3356505.html

    Aaron  分析 Deferred概念 :http://www.cnblogs.com/aaronjs/p/3348569.html
  github:
    when的主页:https://github.com/cujojs/when/
    延迟对象cho45: https://github.com/cho45/jsdeferred
  学习实例:
    whenJS的使用方法,来自蛐蛐的个人博客:https://www.imququ.com/post/promises-when-js.html
    教你一步一步实现一个Promise:http://www.cnblogs.com/ygm125/p/3735677.html
  百科:
    promise规范A+: https://promisesaplus.com/
    维基百科的promise/A规范说明:http://wiki.commonjs.org/wiki/Promises/A  ,打开非常慢
    维基百科的promise/B规范说明:http://wiki.commonjs.org/wiki/Promises/B ,打开也非常慢

  

JS搞基指南----延迟对象入门提高资料整理的更多相关文章

  1. CNN 入门学习资料整理

    建议按序阅读 1. Convolutional Neural Networks卷积神经网络: http://blog.csdn.net/zouxy09/article/details/8781543 ...

  2. RNN 入门学习资料整理

    建议按序阅读 1. RNN的一些简单概念介绍 A guide to recurrent neural networks and backpropagation Deep learning:四十九(RN ...

  3. DBN 入门学习资料整理

    建议按序阅读 1.Deep Learning 概述 Deep Learning(深度学习)学习笔记整理系列 : http://blog.csdn.net/zouxy09/article/details ...

  4. JavaScript学习笔记(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

    一.AJAX示例 AJAX全称为“Asynchronous JavaScript And XML”(异步JavaScript和XML) 是指一种创建交互式网页应用的开发技术.改善用户体验,实现无刷新效 ...

  5. JavaScript学习总结(一)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

    一.AJAX示例 AJAX全称为“Asynchronous JavaScript And XML”(异步JavaScript和XML) 是指一种创建交互式网页应用的开发技术.改善用户体验,实现无刷新效 ...

  6. JavaScript学习总结(二)——延迟对象、跨域、模板引擎、弹出层、AJAX示例

    一.AJAX示例 AJAX全称为“Asynchronous JavaScript And XML”(异步JavaScript和XML) 是指一种创建交互式网页应用的开发技术.改善用户体验,实现无刷新效 ...

  7. Grunt JS构建环境搭建以及使用入门

    Grunt JS构建环境搭建以及使用入门 1.应用场景 一种自动化任务处理工具,对于日常的需求(代码规则检查.代码合并)可以实现自动化执行,只需要保留package.json和Gruntfile.js ...

  8. tween.js 中文使用指南

    tween.js 英文使用指南 首先来看个例子: hello,tween.js 补间(动画)(来自 in-between)是一个概念,允许你以平滑的方式更改对象的属性.你只需告诉它哪些属性要更改,当补 ...

  9. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

随机推荐

  1. HTML标签----图文详解(二)

    HTML标签超详细的图文演示再来一波~~~ 如果还没有看过昨天的福利的,那可要抓紧喽,传送门:HTML标签----图文详解 本文主要内容 列表标签 表格标签 框架标签及内嵌框架<iframe&g ...

  2. linux下安装python

    在Linux下安装Python的操作相当简单,按如下步骤操作即可: 命令: wget https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tgzt ...

  3. dp入门问题

    昨天晚上的rank彻底废了..一个星期没敲代码完全没手感.作为总结,贴一道昨天浪费了我两小时的dp.http://acm.dirring.com/problem.php?cid=1003&pi ...

  4. [转]Asp.net mvc 网站之速度优化 -- 页面缓存

    网站速度优化的一般方法 由于网站最重要的用户体验就是速度,特别是对于电子商务网站而言. 一般网站速度优化会涉及到几个方面: 1. 数据库优化 — 查询字段简历索引,使用数据库连接池和持久化,现在还有种 ...

  5. java 24 - 2 GUI之监听机制和适配器改进窗口关闭

    我们创建了窗体后,就要对窗体进行操作,比如关闭窗口.而这时候就要建立监听机制: 事件监听机制: A:事件源 事件发生的地方 B:事件 就是要发生的事情 C:事件处理 就是针对发生的事情做出的处理方案 ...

  6. 安卓手机已保存WiFi密码查看助手(开源)

    一.需求分析 最近电脑需要连接WiFi,却发现WiFi密码给忘记了.而手机里有保存过的WiFi密码,但是在手机的设置界面看不到. 虽然已经有一些可以查看WiFi密码的app,但是主要还是担心密码被那些 ...

  7. sublime text2 配置代码对齐快捷键

    menu under Preferences → Key Bindings – User [{"keys": ["ctrl+shift+r"], "c ...

  8. Java的super调用案例: super.getClass()返回的是子类自己

    If you override a method from your superclass (or your superclass's superclass etc.), super.theMetho ...

  9. P3376 【模板】网络最大流

    P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...

  10. jquery 实现邮箱输入自动提示功能

    邮箱的广泛使用得益于它的免费,因此很多网站在注册的时候都会直接使用邮箱作为账号名 为了提高用户的体验,很多网站都会实现邮箱输入的自动提示功能,所有自己也实现了一个,先看下效果吧,觉得效果还行的就拿去 ...