js 多个then怎么when thenreturnn

异步编程:When.js快速上手
发表于 日 02:33 | Hits: 1932
前些天我在团内做了一个关于的分享。由于AngularJS大量使用Promise,所以我把基于Promise的异步编程也一并介绍了下。很多东西都是一带而过,这里再记录下。
AngularJS内置的是Kris Kowal的框架,我介绍的是自己用得更多的cujoJS的,两者都是的实现。when.js很小,压缩后只有数kb,gzip后的大小几乎可以忽略。在Node和浏览器环境里都可以使用when.js,唯一需要注意的是:在浏览器使用时,要先加,再引入js文件。
首先,我们看一小段代码():
var getData = function(callback) {
$.getJSON(api, function(data){
callback(data[0]);
var getImg = function(src, callback) {
var img = new Image();
img.onload = function() {
callback(img);
var showImg = function(img) {
$(img).appendTo($('#container'));
getData(function(data) {
getImg(data, function(img) {
showImg(img);
});这段代码完成了三个任务:1)获取数据;2)加载图片;3)显示图片,其中,任务1和2是异步,3是同步,使用的是最常见的callback机制来处理异步逻辑,好处是浅显易懂,缺点是强耦合、不直观、处理异常麻烦等等。
另外一种常见的实现异步编程的方案是事件监听器,例如使用QWrap的CustEvent,让任务成功时fireEvent,那么注册了这个Event的监听器就可以收到这个事件,并收到事件传递过来的数据,Dom标准事件也是采用的这种形式。这种方案也很好理解,代码从略。事件监听可以解耦,可以绑定任意多个监听器,但是依然不直观,而且事件发生之后再绑定的监听器也得不到触发。
我们尝试用when.js改写下这段代码():
var getData = function() {
var deferred = when.defer();
$.getJSON(api, function(data){
deferred.resolve(data[0]);
return deferred.
var getImg = function(src) {
var deferred = when.defer();
var img = new Image();
img.onload = function() {
deferred.resolve(img);
return deferred.
var showImg = function(img) {
$(img).appendTo($('#container'));
.then(getImg)
.then(showImg);看最后三行代码,是不是一目了然,非常的语义化?来看下改写后的任务1、2多了些什么:
var deferred = when.defer();定义了一个deferred对象。
deferred.resolve(data);在异步获取数据完成时,把数据作为参数,调用deferred对象的resolve方法。
return deferred.返回了deferred对象的promise属性。
在Promises/A规范中,每个任务都有三种状态:默认(pending)、完成(fulfilled)、失败(rejected)。
默认状态可以单向转移到完成状态,这个过程叫resolve,对应的方法是deferred.resolve(promiseOrValue);
默认状态还可以单向转移到失败状态,这个过程叫reject,对应的方法是deferred.reject(reason);
默认状态时,还可以通过deferred.notify(update)来宣告任务执行信息,如执行进度;
状态的转移是一次性的,一旦任务由初始的pending转为其他状态,就会进入到下一个任务的执行过程中。
有人可能会觉得奇怪:改变任务状态的resolve和reject方法是定义在deferred对象上,但最后返回的却是deferred的promise属性。这么做一是因为规范就是这么定的,二是可以防止任务状态被外部改变。
then有三个参数,分别是onFulfilled、onRejected、onProgress,通过这三个参数,就可以指定上一个任务在resolve、reject和notify时该如何处理。例如上一个任务被resolve(data),onFulfilled函数就会被触发,data作为它的参数;被reject(reason),那么onRejected就会被触发,收到reason。任何时候,onFulfilled和onRejected都只有其一可以被触发,并且只触发一次;onProgress顾名思义,每次notify时都会被调用。下面是reject和notify的用法():
function run() {
var deferred = when.defer();
var start = 1, end = 100;
(function() {
if(start &= end) {
deferred.notify(start++);
setTimeout(arguments.callee, 50);
deferred.reject('time out!');
return deferred.
run().then(undefined,
function(reason) {
alert(reason);
}, function(s) {
document.getElementById('output').innerHTML = s + '%';
);then会传递错误,也就是说有多个任务串行执行时,我们可以只在最后一个then定义onRejected。只定义了onRejected的then等同于otherwise,也就是说 otherwise(onRejected) 是 then(undefined, onRejected) 的简便写法。
then会在try..catch..的包裹之下执行任务,所以任务的异常都会被when.js捕获,当做失败状态处理,类似这样:
} catch (e) {
deferred.reject(e);
在任务状态改变之后再then,依然可以正常工作,后续任务会立刻执行。如果要在多个任务最后做cleanup工作,而不管之前的任务成功与否,可以用ensure方法。它只接受一个参数onFulfilledOrRejected,始终会执行。另外when.js还有一个always方法,即将废弃,建议大家不要使用。
回到上面加载图片的场景,如果把任务2变为:加载多张图片,全部完成后再执行任务3。这时候需要用到when.all,when.all接受一个promise数组,返回promise,这个promise会在promise数组中每一个promise都resolve之后再resolve。说起来拗口,看代码就明白了():
var getData = function() {
var deferred = when.defer();
$.getJSON(api, function(data){
var data = data.slice(0, 3);
deferred.resolve(data);
return deferred.
var getImg = function(src) {
var deferred = when.defer();
var img = new Image();
img.onload = function() {
deferred.resolve(img);
return deferred.
var showImgs = function(imgs) {
$(imgs).appendTo($('#container'));
var getImgs = function(data) {
var deferreds = [];
for(var i = 0; i & data. i++) {
deferreds.push(getImg(data[i]));
when.all(getData().then(getImgs)).then(showImgs);
如果我们只是想把一个promise数组挨个执行一遍,可以用when.settle:
var promise1 = function() {
var deferred = when.defer();
setTimeout(function() {
deferred.reject('A');
return deferred.
var promise2 = function() {
var deferred = when.defer();
setTimeout(function() {
deferred.resolve('B');
return deferred.
when.settle([promise1(), promise2()]).then(function(result) {
console.log(result); /*
[{&state&:&rejected&,&reason&:&A&},
{&state&:&fulfilled&,&value&:&B&}] */
有时候,我们需要引入任务竞争机制,例如从一批cdn中找到最快的那个,when.any就派上用场了,when.any接受promise数组,在其中任何一个resolve后就接着执行后续任务了。如果要在一批promise中某几个resolve后执行后续任务,可以用when.some,它比when.any多一个howMany的参数。
Promise给异步编程代码带来了巨大的方便,从此我们可以更专注单个任务的实现,promise会很好的替我们解决任务调度问题。when.js提供的功能远远不止本文提到的这些,有兴趣的同学可以前往官方了解更多。
本文链接:
评价列表(0)卡通方式趣解 AngularJS 中的 promise - 文章 - 伯乐在线
& 卡通方式趣解 AngularJS 中的 promise
一天早晨,爹对儿子说:“宝儿,出去看看天气如何!”
每个星期天的早晨,爹都叫小宝拿着超级望远镜去家附近最高的山头上看看天气走势如何,小宝说没问题,我们可以认为小宝在离开家的时候给了他爹一个promise。
这时候,他爹就想了,如果明天艳阳高照,他就准备去钓鱼,如果天实在不行,就作罢,如果小宝对预报明天的天气也没底,他就在家宅一天哪也不去。
大概过了半小时,小宝回来了。每周的结果不尽相同:
A计划 :天气晴朗
小宝不辱使命,说外面阳光明媚,万里无云,这个promise was resolved(小宝信守承诺),爹就可以收拾行装,钓鱼去鸟。
B计划: 小宝日观天象,阴转小雨的节奏
小宝依然不辱使命,但是天公不作美,promise was resolved,但是孩儿他爹觉得还是搁家呆着吧。
C计划:天象诡谲,小宝无法做出天气走势判断
小宝败兴而归,云雾重重,遮蔽了视线,不敢妄言天气走势,小宝走的时候立下承诺说要给他爹预报天气,但是没有成功,我们说promise was rejected!孩儿他爹决定小心驶得万年船,还是在家吧。
上述种种,用代码写出来是什么样子呢?
我们可以把孩儿他爹看成controller,小宝就是service。
整理逻辑:孩儿他爹让小宝去看天气,小宝不能立刻告诉他,但是孩儿他爹在等待结果的这段时间里可以抽抽烟,喝喝茶啥的,因为小宝承诺会把天气情况搞清楚。等小宝把天气预报带回来,他就可以决定下一步干啥。各位看官注意了:小宝登高望远看天气的时候并没有影响他爹干别的事情,这就是promise的妙处所在。
Angular里有个then()函数,我们可以决定孩儿他爹到底是用哪个计划(A,B,C),then()接收两个functions作为参数,第一个在promise is resolved的时候执行,另一个在promise is rejected的时候执行
Controller: FatherCtrl
孩儿他爹掌控局面的代码如下:
JavaScript
// function somewhere in father-controller.js
var makePromiseWithSon = function() {
// This service's function returns a promise, but we'll deal with that shortly
SonService.getWeather()
// then() called when son gets back
.then(function(data) {
// promise fulfilled
if (data.forecast==='good') {
prepareFishingTrip();
prepareSundayRoastDinner();
}, function(error) {
// promise rejected, could log the error with: console.log('error', error);
prepareSundayRoastDinner();
1234567891011121314151617
// function somewhere in father-controller.js &&&&var makePromiseWithSon = function() { &&&&&&&&// This service's function returns a promise, but we'll deal with that shortly &&&&&&&&SonService.getWeather() &&&&&&&&&&&&// then() called when son gets back &&&&&&&&&&&&.then(function(data) { &&&&&&&&&&&&&&&&// promise fulfilled &&&&&&&&&&&&&&&&if (data.forecast==='good') { &&&&&&&&&&&&&&&&&&&&prepareFishingTrip(); &&&&&&&&&&&&&&&&} else { &&&&&&&&&&&&&&&&&&&&prepareSundayRoastDinner(); &&&&&&&&&&&&&&&&} &&&&&&&&&&&&}, function(error) { &&&&&&&&&&&&&&&&// promise rejected, could log the error with: console.log('error', error); &&&&&&&&&&&&&&&&prepareSundayRoastDinner(); &&&&&&&&&&&&}); &&&&};
Service: SonService
小宝的作用就是充当了一个service,他爬上山头看天象,有点类似调用weather API,而且还是异步调用,他得到的结果可能是个变量,也有可能出现异常情况(比如,返回500—&大雾弥漫)。
从”Fishing Weather API”返回一个promise,如果it was resolved,就格式化成{“forecase”:”good”}。
JavaScript
app.factory('SonService', function ($http, $q) {
getWeather: function() {
// the $http API is based on the deferred/promise APIs exposed by the $q service
// so it returns a promise for us by default
return $http.get('http://fishing-/sunday/afternoon')
.then(function(response) {
if (typeof response.data === 'object') {
return response.
// invalid response
return $q.reject(response.data);
}, function(response) {
// something went wrong
return $q.reject(response.data);
123456789101112131415161718192021
app.factory('SonService', function ($http, $q) { &&&&return { &&&&&&&&getWeather: function() { &&&&&&&&&&&&// the $http API is based on the deferred/promise APIs exposed by the $q service &&&&&&&&&&&&// so it returns a promise for us by default &&&&&&&&&&&&return $http.get('http://fishing-/sunday/afternoon') &&&&&&&&&&&&&&&&.then(function(response) { &&&&&&&&&&&&&&&&&&&&if (typeof response.data === 'object') { &&&&&&&&&&&&&&&&&&&&&&&&return response.data; &&&&&&&&&&&&&&&&&&&&} else { &&&&&&&&&&&&&&&&&&&&&&&&// invalid response &&&&&&&&&&&&&&&&&&&&&&&&return $q.reject(response.data); &&&&&&&&&&&&&&&&&&&&}& &&&&&&&&&&&&&&&&}, function(response) { &&&&&&&&&&&&&&&&&&&&// something went wrong &&&&&&&&&&&&&&&&&&&&return $q.reject(response.data); &&&&&&&&&&&& }); &&&&&&&&} &&&&}; });
这个比喻向我们展示了异步的实质,孩儿他爹不会倚门等待儿子的归来,这段时间他完全可以自由活动。 孩儿他爹到底用哪个计划取决于(天气好/坏,没有成功预报),小宝在临走的时候给他爹一个promise,就等他回来的时候决定是resolve还是reject。
小宝其实是在使用异步服务(观天象—调用weather API)来获取天气信息,孩儿他爹根本就不懂技术,坐等结果即可!
关于作者:
可能感兴趣的话题
最近正好在学angularJs,这篇文章讲的很生动形象啊!
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2016 伯乐在线jQuery回调、递延对象总结(中篇) ―― 神奇的then方法
什么叫做递延对象,生成一个递延对象只需调用jQuery.Deferred函数,deferred这个单词译为延期,推迟,即延迟的意思,那么在jQuery中
又是如何表达延迟的呢,从递延对象中的then方法或许能找到这种延迟的行为,本文重点解读递延对象中的then方法
上一篇:jQuery回调、递延对象总结(上篇)&& jQuery.Callbacks
设计思路:
在递延对象构造中,分别有三组回调对象,每一组回调对象都有与之对应的行为(action,add listener),和状态(final state),
这些行为都归纳为递延对象中的(触发回调,添加函数到回调列表中等)方法
jQuery.Deferred构造
Deferred构造源码除了then函数源码外,其他都非常简单,这里不做过多解读,后面将重点讨论then方法
&View Code
神奇的then方法
在实际项目应用中,一个页面或许有多个ajax请求,你可能会这样做:
$.ajax({ url1, ... });
$.ajax({ url2, ... });
$.ajax({ url3, ... });
这样做的缺点:
1、多个ajax同时发送请求,可能会造成服务器压力,对于富应用页面来说,如果请求过多,那是必然的;
2、对于页面底部,或者说首屏不展示给用户浏览的部分需要发送的ajax请求,没有必要让它一开始加载页面后就发送请求,这样会造成页面响应缓慢
jQuery递延对象中的then方法好像天生就是为了解决以上问题而设计的,它可以按照顺序依次处理多个异步请求,即第一个请求处理完后,
再处理第二个请求,以此类推,这样既可以减轻服务器压力,又可以先发送首屏(从上到下)页面部分的请求,使页面响应更快
来看看一段非常优雅的实例代码
var promiseA = $.get(urlA);
promiseA.always(doneFnA, failFnA, progressFnA);
var promiseB = promiseA.then(function(){
& & return $.get(urlB);
或者你也可以这样写,但并不建议:
&View Code
上面代码是如何运行的呢:
首先发送第一个ajax请求,当promiseA对象执行过resolve(或reject、notify)后,即:第一个请求成功或失败后,将依次执行回调doneFnA
(或failFnA、progressFnA),then中的匿名函数(注意代码的顺序,之前代码顺序有误,把promiseA.always放在了then方法执行之后,现已改过来了),
匿名函数中发送第二个ajax请求,当请求成功或失败后,将执行对应的回调函数(doneFnB或failFnB、progressFnB)
衍生后的代码
var promiseA = $.get(urlA);
// 这里添加promiseA的回调
var promiseB = promiseA.then(function(){
& & return $.get(urlB);
// 这里添加promiseB的回调
var promiseC = promiseB.then(function(){
& & return $.get(urlC);
// 这里添加promiseC的回调
var promiseD = promiseC.then(function(){
& & return $.get(urlD);
// 这里添加promiseD的回调
再来看看then函数中的构造源码,通过上面的实例分析,相信眼前的你会恍然大悟的
promise = {
& & then: function( /* fnDone, fnFail, fnProgress */ ) {
& & & & var fns =
& & & & // 返回后的promise对象与newDefer对应
& & & & return jQuery.Deferred(function( newDefer ) {
& & & & & & jQuery.each( tuples, function( i, tuple ) {
& & & & & & & & var action = tuple[ 0 ],
& & & & & & & & & & fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
& & & & & & & & // deferred[ done | fail | progress ] for forwarding actions to newDefer
& & & & & & & & // 为第一个递延对象添加回调
& & & & & & & & deferred[ tuple[1] ](function() {
& & & & & & & & & & var returned = fn && fn.apply( this, arguments );
& & & & & & & & & & // 如果回调返回的是一个递延对象,newDefer将根据这个返回的递延对象的状态来触发行为
& & & & & & & & & & if ( returned && jQuery.isFunction( returned.promise ) ) { &&
& & & & & & & & & & & &&
& & & & & & & & & & & & returned.promise()
& & & & & & & & & & & & & & .done( newDefer.resolve )
& & & & & & & & & & & & & & .fail( newDefer.reject )
& & & & & & & & & & & & & & .progress( newDefer.notify );
& & & & & & & & & & }
& & & & & & & & & & // 如果回调返回的不是一个递延对象,newDefer将根据第一个(deferred)递延对象的状态来触发行为
& & & & & & & & & & else {
& & & & & & & & & & & & newDefer[ action + &With& ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
& & & & & & & & & & }
& & & & & & & & });
& & & & & & });
& & & & & & fns =
& & & & }).promise();
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'&&国之画&&&&&&
版权所有 京ICP备号-2
迷上了代码!JavaScript异步回调 then.js
JavaScript异步回调 then.js
JavaScript异步回调 then.js
Another very small promise!
能用简单优美的方式将任何同步或异步回调函数转换成then()链式调用!
then.js不同于其它promise,它没有resolve、也没有reject、更没有promise对象,所以你不再需要把异步任务封装成promise对象。
一个典型的promise都要封装:
function getFile() {
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
if (error) {
deferred.reject(new Error(error));
deferred.resolve(text);
return deferred.
getFile().then(successHandler[, errorHandler]);
若要进入下一个then链,上面then中的successHandler、errorHandler还得进行如上类似封装,搞得挺复杂!
then.js只有then对象,它包括then、all和fail三个方法和触发器defer,无需封装,直接将异步任务写入then()!因为then、all和fail都能自动生成下一个then对象,reject和resolve被合并为defer并注入任务函数,reject和resolve合并为defer的好处是,简化代码,还可以直接代替callback!
then.js使用模式
then(function (defer) {
defer(err, ...);
}).then(function (defer, value) {
defer(err, ...);
}, function (defer, err) {
defer(err, ...);
}).then(function (defer) {
defer(err, ...);
}).all(function (defer, err, value) {
defer(err, ...);
}).then(function (defer) {
defer(err, ...);
}).fail(function (defer, err) {
then(function (defer) {
defer(err, ...);
}).then(function (defer, value) {
then(function (defer2) {
defer2(err, ...);
}).then(function (defer2, value) {
then(function (defer3) {
}).all(defer2); // 返回二层
}).then(function (defer2) {
defer(err, ...); // 返回一层
}).fail(defer); // 返回一层
}).then(function (defer) {
defer(err, ...);
}).fail(function (defer, err) {
async 嵌套:
then(function (defer) {
defer(err, array);
}).then(function (defer, array) {
then.each(array, function (next, value) {
// ....逐步执行同步或异步任务
return next ? next() : defer();
}).then(function (defer) {
defer(err, ...);
}).fail(function (defer, err) {
then对象取代callback:
function getFileAsync() {
return then(function (defer) {
readFile(failname, defer);
}).then(function (defer, fileContent) {
// 处理fileContent
defer(null, result);
}).fail(function (defer, err) {
// 处理error
defer(err);
getFileAsync().then(function (defer, file) {
}).fail(function(defer, err) {
更多用法请参考源代码,里面包含了一百多个then任务链,几百个then对象!
promise模式:
入口函数then():
var thenObj = then(function(defer) {
// 执行同步或异步任务
defer(err, result1, ...);
// 入口函数返回then对象
then对象的then方法:
thenObj.then(function(defer, successResult, ...) {
// Success Handler
// 执行同步或异步任务
defer(err, result1, ...);
}, function(defer, successResult, ...) {
// Error Handler,可选
// 执行同步或异步任务
defer(err, result1, ...);
// then方法返回新的then对象(即下一个then链)
then对象的all方法:
thenObj.all(function(defer, err, successResult, ...) {
// All Handler
// 执行同步或异步任务
defer(err, result1, ...);
// all方法返回新的then对象(即下一个then链)
then对象的fail方法:
thenObj.fail(function(defer, err) {
// Error Handler
// 执行同步或异步任务
defer(err, result1, ...);
// fail方法返回新的then对象(即下一个then链)
关于Error收集器
then对象的then方法的errorHandler函数、all方法、fail方法均能收集error。其中then方法的errorHandler函数和all方法只能收集上一个then对象产生的error;fail方法则能收集再它之前所有then链产生的error。
关于触发器defer
then.js中最关键的就是defer,用于触发下一个then链。从上面可知,入口函数、then方法、all方法、fail方法中的任务函数的第一个参数都被注入了defer方法,如果任务函数本身是一个defer方法,则不会再被注入defer方法。
defer的第一个参数永远是error,如果error存在,则error下一个then对象的Error收集器,如果Error收集器不存在,则抛出error。
如果异步任务的callback的第一个参数为error,即callback(error, result1, …)的形式,则可直接用defer代替异步任务的callback。Node.js中的异步函数基本都是这种形式,then.js用起来超方便。
关于fail方法
fail方法能捕捉在它之前的then链中的任何一个error。fail的优先级低于then方法的errorHandler和all方法,即then对象不存在then方法的errorHandler和all方法时error才会进入fail。当then链的某个then对象产生了error时,如果该then对象的下一个then对象存在Error收集器,则error进入该Error收集器,否则error会直接进入then链下游最近的fail方法,其间的then对象均会跳过。
async模式:
then.each(array, function (next, value, index, array) {
// 逐步执行同步或异步任务
asyncTask(value, function () {
return next ? next() : callback();
npm install thenjs
var then = require('thenjs');
注意:then.js需要bind方法支持,IE8及以下请先加载es5-shim.js
then(function (defer) {
// start asnys task
// use defer as callback function
asnycTask1(param, defer);
then(function (defer, value1, ...) {
// successHandler, value1, ... from asnycTask1
asnycTask2(value1, ..., defer);
}, function (defer, err) {
// errorHandler, err from asnycTask1
console.error(err);
then(function (defer, value) {
// successHandler, value from asnycTask2
asnycTask3(value, defer);
then(function (defer, value) {
// successHandler, value from asnycTask3
asnycTask4(value, defer);
fail(function (defer, err) {
// global errorHandler, err from asnycTask2 or asnycTask3
console.error(err);
No tags for this post.
JavaScript异步回调 then.js
Another very small promise!
能用简单优美的方式将任何同步或异步回调函数转换成then()链式调用!
then.js不同于其它promise,它没有resolve、也没有reject、更没有promise对象,所以你不再需要把异步任务封装成promise对象。
一个典型的promise都要封装:
function getFile() {
var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (error, text) {
if (error) {
deferred.reject(new Error(error));
deferred.resolve(text);
return deferred.
getFile().then(successHandler[, errorHandler]);
若要进入下一个then链,上面then中的successHandler、errorHandler还得进行如上类似封装,搞得挺复杂!
then.js只有then对象,它包括then、all和fail三个方法和触发器defer,无需封装,直接将异步任务写入then()!因为then、all和fail都能自动生成下一个then对象,reject和resolve被合并为defer并注入任务函数,reject和resolve合并为defer的好处是,简化代码,还可以直接代替callback!
then.js使用模式
then(function (defer) {
defer(err, ...);
}).then(function (defer, value) {
defer(err, ...);
}, function (defer, err) {
defer(err, ...);
}).then(function (defer) {
defer(err, ...);
}).all(function (defer, err, value) {
defer(err, ...);
}).then(function (defer) {
defer(err, ...);
}).fail(function (defer, err) {
then(function (defer) {
defer(err, ...);
}).then(function (defer, value) {
then(function (defer2) {
defer2(err, ...);
}).then(function (defer2, value) {
then(function (defer3) {
}).all(defer2); // 返回二层
}).then(function (defer2) {
defer(err, ...); // 返回一层
}).fail(defer); // 返回一层
}).then(function (defer) {
defer(err, ...);
}).fail(function (defer, err) {
async 嵌套:
then(function (defer) {
defer(err, array);
}).then(function (defer, array) {
then.each(array, function (next, value) {
// ....逐步执行同步或异步任务
return next ? next() : defer();
}).then(function (defer) {
defer(err, ...);
}).fail(function (defer, err) {
then对象取代callback:
function getFileAsync() {
return then(function (defer) {
readFile(failname, defer);
}).then(function (defer, fileContent) {
// 处理fileContent
defer(null, result);
}).fail(function (defer, err) {
// 处理error
defer(err);
getFileAsync().then(function (defer, file) {
}).fail(function(defer, err) {
更多用法请参考源代码,里面包含了一百多个then任务链,几百个then对象!
promise模式:
入口函数then():
var thenObj = then(function(defer) {
// 执行同步或异步任务
defer(err, result1, ...);
// 入口函数返回then对象
then对象的then方法:
thenObj.then(function(defer, successResult, ...) {
// Success Handler
// 执行同步或异步任务
defer(err, result1, ...);
}, function(defer, successResult, ...) {
// Error Handler,可选
// 执行同步或异步任务
defer(err, result1, ...);
// then方法返回新的then对象(即下一个then链)
then对象的all方法:
thenObj.all(function(defer, err, successResult, ...) {
// All Handler
// 执行同步或异步任务
defer(err, result1, ...);
// all方法返回新的then对象(即下一个then链)
then对象的fail方法:
thenObj.fail(function(defer, err) {
// Error Handler
// 执行同步或异步任务
defer(err, result1, ...);
// fail方法返回新的then对象(即下一个then链)
关于Error收集器
then对象的then方法的errorHandler函数、all方法、fail方法均能收集error。其中then方法的errorHandler函数和all方法只能收集上一个then对象产生的error;fail方法则能收集再它之前所有then链产生的error。
关于触发器defer
then.js中最关键的就是defer,用于触发下一个then链。从上面可知,入口函数、then方法、all方法、fail方法中的任务函数的第一个参数都被注入了defer方法,如果任务函数本身是一个defer方法,则不会再被注入defer方法。
defer的第一个参数永远是error,如果error存在,则error下一个then对象的Error收集器,如果Error收集器不存在,则抛出error。
如果异步任务的callback的第一个参数为error,即callback(error, result1, …)的形式,则可直接用defer代替异步任务的callback。Node.js中的异步函数基本都是这种形式,then.js用起来超方便。
关于fail方法
fail方法能捕捉在它之前的then链中的任何一个error。fail的优先级低于then方法的errorHandler和all方法,即then对象不存在then方法的errorHandler和all方法时error才会进入fail。当then链的某个then对象产生了error时,如果该then对象的下一个then对象存在Error收集器,则error进入该Error收集器,否则error会直接进入then链下游最近的fail方法,其间的then对象均会跳过。
async模式:
then.each(array, function (next, value, index, array) {
// 逐步执行同步或异步任务
asyncTask(value, function () {
return next ? next() : callback();
npm install thenjs
var then = require('thenjs');
注意:then.js需要bind方法支持,IE8及以下请先加载es5-shim.js
then(function (defer) {
// start asnys task
// use defer as callback function
asnycTask1(param, defer);
then(function (defer, value1, ...) {
// successHandler, value1, ... from asnycTask1
asnycTask2(value1, ..., defer);
}, function (defer, err) {
// errorHandler, err from asnycTask1
console.error(err);
then(function (defer, value) {
// successHandler, value from asnycTask2
asnycTask3(value, defer);
then(function (defer, value) {
// successHandler, value from asnycTask3
asnycTask4(value, defer);
fail(function (defer, err) {
// global errorHandler, err from asnycTask2 or asnycTask3
console.error(err);
No tags for this post.
发表评论:
TA的最新馆藏[转]&}

我要回帖

更多关于 if then return 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信