我想在Node.js中创建一系列异步方法,例如:
function functionA(data, callback){
console.log("A")
// do something here
callback();
}
function functionB(data, callback){
console.log("B");
// do something here
callback();
}
function functionC(data, callback){
console.log("C");
// do something here
callback();
}
每个函数都是独立的,但是当链接在一起时,可以有序地调用它们。例如:
functionA(data).functionC(data).functionB(data)
将打印A
,然后C
再B
。可以无限制地重新排列链的顺序。这是我被搜索到的内容:
这就是我为什么async
没有我期望的答案的原因。
考虑会计问题,如果有一笔总额为1200美元的卖出交易,首先我必须将1200美元放入资产:现金簿(借方),然后我必须将1200美元放入收入簿(贷方)。它可以与异步吗?是的当然。它看起来像这样:
async.series([
function(callback){
bookLibrary.debit('cash', 1200, callback);
},
function(callback){
bookLibrary.credit('income', 1200, callback);
}
]);
因此,我想通过链接它们使它更简单易读,如下所示:
bookLibrary.debit('cash', 1200).credit('income', 1200)
首先,要链接一堆函数,您需要将它们配置为公共对象上的方法。然后,每个方法都可以返回该对象,因此返回结果是该对象,并且可以在该对象上调用下一个方法。
因此,要做这样的事情:
a().b().c();
您需要a()
返回一个具有方法的对象b()
作为属性。并且,类似地,您需要a().b()
返回具有c()
其作为属性的对象。这通常称为Fluent接口。就同步方法而言,这本身就非常简单。这正是jQuery进行链接的方式。
$(".foo").show().css("color", "blue");
所有这三个调用都返回一个jQuery对象,并且该jQuery对象包含您可以链接的所有方法。
在上面的示例中,您可以像这样进行同步链接:
function a() {
}
a.prototype = {
b: function() {
// do something
return this;
},
c: function() {
// do something else
return this;
}
};
但是,您的问题是关于异步操作的。那显然是更多的工作,因为当您这样做时:
a().b().c();
这将立即一个接一个地执行所有三个方法,而不会等待它们中的任何一个完成。使用这种确切的语法,我所知道的支持链接的唯一方法是建立一个队列,在该队列中.b(xxx)
,对象实际上不是立即执行,而是将该操作a()
排入队列,直到完成为止。jQuery就是这样制作动画的:
$(".foo").slideUp().slideDown();
因此,从每个方法返回的对象可以包含一个队列,当一个操作完成时,该对象然后从队列中提取下一个项目,为其分配参数(也保留在队列中),执行该参数并对其进行监视进行异步操作,再次从队列中提取下一个项目。
这是队列的一般想法。当我进入这个实现时,我意识到诺言将使这变得容易得多。这是不使用promise(未经测试)的实现的一般想法:
为了简化异步操作示例,让makea()
执行10ms setTimeout,.b()
50ms setTimeout和.c()
100ms setTimeout。实际上,这些可以是完成后调用回调的任何异步操作。
function a() {
if (!(this instanceof a)) {
return new a();
} else {
this.queue = [];
this.inProgress = false;
this.add(function(callback) {
// here our sample 10ms async operation
setTimeout(function() {
callback(null);
}, 10);
}, arguments);
}
}
a.prototype = {
b: function() {
this.add(function(callback) {
// here our sample 50ms async operation
setTimeout(function() {
callback(null);
}, 50);
return this;
}, arguments);
},
c: function(t) {
this.add(function(t, callback) {
// here our sample 100ms async operation
setTimeout(function() {
callback(null);
}, t);
return this;
}, arguments);
},
add: function(fn, args) {
// make copy of args
var savedArgs = Array.prototype.slice.call(args);
this.queue.push({fn: fn, args:savedArgs});
this._next();
},
_next: function() {
// execute the next item in the queue if one not already running
var item;
if (!this.inProgress && this.queue.length) {
this.inProgress = true;
item = this.queue.shift();
// add custom callback to end of args
item.args.push(function(err) {
this.inProgress = false;
if (err) {
// clear queue and stop execution on an error
this.queue = [];
} else {
// otherwise go to next queued operation
this._next();
}
});
try {
item.fn.apply(this, item.args);
} catch(e) {
// stop on error
this.queue = [];
this.inProgress = false;
}
}
}
};
// usage
a().b().c(100);
如果我们在异步操作和排队中都使用promise,那么事情就会变得简单一些:
所有异步操作(例如firstAsyncOperation
和)都会secondAsyncOperation
返回一个Promise,从而大大简化了事情。异步链接是由Promise基础结构为我们完成的。
function a(arg1, arg2) {
if (!(this instanceof a)) {
return new a(arg1, arg2);
} else {
this.p = firstAsyncOperation(arg1, arg2);
}
}
a.prototype = {
b: function() {
return this._chain(secondAsyncOperation, arguments);
},
c: function() {
return this._chain(thirdAsyncOperation, arguments);
},
_chain: function(fn, args) {
var savedArgs = Array.prototype.slice.call(args);
this.p = this.p.then(function() {
return fn.apply(this, savedArgs);
});
return this;
},
then: function(a, b) {
this.p = this.p.then(a, b);
return this;
},
catch: function(fn) {
this.p = this.p.catch(fn);
return this;
}
};
// usage:
a().b().c(100).then(function() {
// done here
}).catch(function() {
// error here
});
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句