这篇文章,我们一起探索一下 javascript 中的 deferred 和 promise 的概念,它们是 javascript 工具包(如dojo和mochikit)中非常重要的一个功能,最近也首次亮相于 流行的 javascript 库 jquery(已经是1.5版本的事情了)。 deferred 提供了一个抽象的非阻塞的解决方案(如 ajax 请求的响应),它创建一个 “promise” 对象,其目的是在未来某个时间点返回一个响应。如果您之前没有接触过 “promise”,我们将会在下面做详细介绍。
抽象来说,deferreds 可以理解为表示需要长时间才能完成的耗时操作的一种方式,相比于阻塞式函数它们是异步的,而不是阻塞应用程序等待其完成然后返回结果。deferred对 象会立即返回,然后你可以把回调函数绑定到deferred对象上,它们会在异步处理完成后被调用。
promise
你可能已经过一些关于promise和deferreds实现细节的资料。在本章节中,我们大致介绍下promise如何工作,这些在几乎所有的支持deferreds的javascript框架中都是适用的。
一般情况下,promise作为一个模型,提供了一个在软件工程中描述延时(或将来)概念的解决方案。它背后的思想我们已经介绍过:不是执行一个方法然后阻塞应用程序等待结果返回,而是返回一个promise对象来满足未来值。
举一个例子会有助于理解,假设你正在建设一个web应用程序, 它很大程度上依赖第三方api的数据。那么就会面临一个共同的问题:我们无法获悉一个api响应的延迟时间,应用程序的其他部分可能会被阻塞,直到它返回 结果。deferreds 对这个问题提供了一个更好的解决方案,它是非阻塞的,并且与代码完全解耦 。
promise/a提议'定义了一个'then‘方法来注册回调,当处理函数返回结果时回调会执行。它返回一个promise的伪代码看起来是这样的:
. 代码如下:
promise = calltoapi( arg1, arg2, ...);
promise.then(function( futurevalue ) {
/* handle futurevalue */
});
promise.then(function( futurevalue ) {
/* do something else */
});
. 代码如下:
promise.then( function( futurevalue ) {
/* we got a value */
} , function() {
/* something went wrong */
} );
. 代码如下:
when(
promise1,
promise2,
...
).then(function( futurevalue1, futurevalue2, ... ) {
/* all promises have completed and are resolved */
});
. 代码如下:
when( function(){
/* animation 1 */
/* return promise 1 */
}, function(){
/* animation 2 */
/* return promise 2 */
} ).then(function(){
/* once both animations have completed we can then run our additional logic */
});
jquery.deferred() | 创建一个新的deferred对象的构造函数,可以带一个可选的函数参数,它会在构造完成后被调用。 |
jquery.when() | 通过该方式来执行基于一个或多个表示异步任务的对象上的回调函数 |
jquery.ajax() | 执行异步ajax请求,返回实现了promise接口的jqxhr对象 |
deferred.then(resolvecallback,rejectcallback) | 添加处理程序被调用时,递延对象得到解决或者拒绝的回调。 |
deferred.done() |
当延迟成功时调用一个函数或者数组函数. |
deferred.fail() |
当延迟失败时调用一个函数或者数组函数.。 |
deferred.resolve(arg1,arg2,...) | 调用deferred对象注册的‘done'回调函数并传递参数 |
deferred.resolvewith(context,args) | 调用deferred对象注册的‘done'回调函数并传递参数和设置回调上下文 |
deferred.isresolved | 确定一个deferred对象是否已经解决。 |
deferred.reject(arg1,arg2,...) | 调用deferred对象注册的‘fail'回调函数并传递参数 |
deferred.rejectwith(context,args) | 调用deferred对象注册的‘fail'回调函数并传递参数和设置回调上下文 |
deferred.promise() | 返回promise对象,这是一个伪造的deferred对象:它基于deferred并且不能改变状态所以可以被安全的传递 |
. 代码如下:
function successfunc(){ console.log( “success!” ); }
function failurefunc(){ console.log( “failure!” ); }
$.when(
$.ajax( "/main.php" ),
$.ajax( "/modules.php" ),
$.ajax( “/lists.php” )
).then( successfunc, failurefunc );
. 代码如下:
function getlatestnews() {
return $.get( “latestnews.php”, function(data){
console.log( “news data received” );
$( “.news” ).html(data);
} );
}
function getlatestreactions() {
return $.get( “latestreactions.php”, function(data){
console.log( “reactions data received” );
$( “.reactions” ).html(data);
} );
}
function prepareinterface() {
return $.deferred(function( dfd ) {
var latest = $( “.news, .reactions” );
latest.slidedown( 500, dfd.resolve );
latest.addclass( “active” );
}).promise();
}
$.when(
getlatestnews(), getlatestreactions(), prepareinterface()
).then(function(){
console.log( “fire after requests succeed” );
}).fail(function(){
console.log( “something went wrong!” );
});
. 代码如下:
$.cachedgetscript( url, callback1 );
$.cachedgetscript( url, callback2 );
. 代码如下:
var cachedscriptpromises = {};
$.cachedgetscript = function( url, callback ) {
if ( !cachedscriptpromises[ url ] ) {
cachedscriptpromises[ url ] = $.deferred(function( defer ) {
$.getscript( url ).then( defer.resolve, defer.reject );
}).promise();
}
return cachedscriptpromises[ url ].done( callback );
};
. 代码如下:
$.createcache = function( requestfunction ) {
var cache = {};
return function( key, callback ) {
if ( !cache[ key ] ) {
cache[ key ] = $.deferred(function( defer ) {
requestfunction( defer, key );
}).promise();
}
return cache[ key ].done( callback );
};
}
. 代码如下:
$.cachedgetscript = $.createcache(function( defer, url ) {
$.getscript( url ).then( defer.resolve, defer.reject );
});
. 代码如下:
$.loadimage = $.createcache(function( defer, url ) {
var image = new image();
function cleanup() {
image.onload = image.onerror = null;
}
defer.then( cleanup, cleanup );
image.onload = function() {
defer.resolve( url );
};
image.onerror = defer.reject;
image.src = url;
});
. 代码如下:
$.loadimage( "my-image.png" ).done( callback1 );
$.loadimage( "my-image.png" ).done( callback2 );
. 代码如下:
$.searchtwitter = $.createcache(function( defer, query ) {
$.ajax({
url: "http://search.twitter.com/search.json",
data: { q: query },
datatype: "jsonp",
success: defer.resolve,
error: defer.reject
});
});
. 代码如下:
$.searchtwitter( "jquery deferred", callback1 );
$.searchtwitter( "jquery deferred", callback2 );
. 代码如下:
var readytime;
$(function() { readytime = jquery.now(); });
$.afterdomready = $.createcache(function( defer, delay ) {
delay = delay || 0;
$(function() {
var delta = $.now() - readytime;
if ( delta >= delay ) { defer.resolve(); }
else {
settimeout( defer.resolve, delay - delta );
}
});
});
. 代码如下:
$.fn.animatepromise = function( prop, speed, easing, callback ) {
var elements = this;
return $.deferred(function( defer ) {
elements.animate( prop, speed, easing, function() {
defer.resolve();
if ( callback ) {
callback.apply( this, arguments );
}
});
}).promise();
};
. 代码如下:
var fadediv1out = $( "#p1" ).animatepromise({ opacity: 0 }),
fadediv2in = $( "#p1" ).animatepromise({ opacity: 1 }, "fast" );
$.when( fadediv1out, fadediv2in ).done(function() {
/* both animations ended */
});
. 代码如下:
$.each([ "slidedown", "slideup", "slidetoggle", "fadein", "fadeout", "fadetoggle" ],
function( _, name ) {
$.fn[ name + "promise" ] = function( speed, easing, callback ) {
var elements = this;
return $.deferred(function( defer ) {
elements[ name ]( speed, easing, function() {
defer.resolve();
if ( callback ) {
callback.apply( this, arguments );
}
});
}).promise();
};
});
. 代码如下:
$.when(
$( "#p1" ).fadeoutpromise(),
$( "#p2" ).fadeinpromise( "fast" )
).done(function() {
/* both animations are done */
});
. 代码如下:
var buttonclicked = false;
$( "#mybutton" ).click(function() {
if ( !buttonclicked ) {
buttonclicked = true;
initializedata();
showpanel();
}
});
. 代码如下:
if ( buttonclicked ) { /* perform specific action */ }
. 代码如下:
$.fn.bindonce = function( event, callback ) {
var element = $( this[ 0 ] ),
defer = element.data( "bind_once_defer_" + event );
if ( !defer ) {
defer = $.deferred();
function defercallback() {
element.unbind( event, defercallback );
defer.resolvewith( this, arguments );
}
element.bind( event, defercallback )
element.data( "bind_once_defer_" + event , defer );
}
return defer.done( callback ).promise();
};
. 代码如下:
$.fn.firstclick = function( callback ) {
return this.bindonce( "click", callback );
};
. 代码如下:
var openpanel = $( "#mybutton" ).firstclick();
openpanel.done( initializedata );
openpanel.done( showpanel );
. 代码如下:
openpanel.done(function() { /* perform specific action */ });
. 代码如下:
var panel = $( "#mypanel" );
panel.firstclick(function() {
$.when(
$.get( "panel.html" ),
panel.slidedownpromise()
).done(function( ajaxresponse ) {
panel.html( ajaxresponse[ 0 ] ).fadein();
});
});
. 代码如下:
<p id="mypanel">
<img data-src="image1.png" />
<img data-src="image2.png" />
<img data-src="image3.png" />
<img data-src="image4.png" />
</p>
. 代码如下:
$( "#mybutton" ).firstclick(function() {
var panel = $( "#mypanel" ),
promises = [];
$( "img", panel ).each(function() {
var image = $( this ), src = element.attr( "data-src" );
if ( src ) {
promises.push(
$.loadimage( src ).then( function() {
image.attr( "src", src );
}, function() {
image.attr( "src", "error.png" );
} )
);
}
});
promises.push( panel.slidedownpromise() );
$.when.apply( null, promises ).done(function() { panel.fadein(); });
});
. 代码如下:
<img data-src="image1.png" data-after="1000" src="placeholder.png" />
<img data-src="image2.png" data-after="1000" src="placeholder.png" />
<img data-src="image1.png" src="placeholder.png" />
<img data-src="image2.png" data-after="2000" src="placeholder.png" />
. 代码如下:
$( "img" ).each(function() {
var element = $( this ),
src = element.attr( "data-src" ),
after = element.attr( "data-after" );
if ( src ) {
$.when(
$.loadimage( src ),
$.afterdomready( after )
).then(function() {
element.attr( "src", src );
}, function() {
element.attr( "src", "error.png" );
} ).done(function() {
element.fadein();
});
}
});
. 代码如下:
$( "img" ).each(function() {
var element = $( this ),
src = element.attr( "data-src" ),
after = element.attr( "data-after" );
if ( src ) {
$.afterdomready( after, function() {
$.loadimage( src ).then(function() {
element.attr( "src", src );
}, function() {
element.attr( "src", "error.png" );
} ).done(function() {
element.fadein();
});
} );
}
});
如对本文有疑问, 点击进行留言回复!!
轻松解决 org.apache.taglibs.standard.tlv.JstlCoreTLV 困惑
vert实践五——Json?Protocol Buffer?FlatBuffers?
[基于tensorflow的人脸检测] 基于神经网络的人脸检测8——验证训练好的神经网络
selenium + ajax抓取英雄联盟全部英雄的详细信息及多线程保存全部皮肤图片到本地
网友评论