gpt4 book ai didi

javascript - 如何在node.js中创建异步方法链?

转载 作者:行者123 更新时间:2023-12-02 13:48:32 25 4
gpt4 key购买 nike

我想在 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。链条的顺序可以不受限制地重新排列。以下是我搜索到的内容:

  1. Create chained methods in node.js? , --> 这是关于这个主题的上一个问题,非常古老,也不是异步的
  2. http://www.dustindiaz.com/async-method-queues/ --> 取决于 jquery、客户端脚本,不是 Node ,不是异步
  3. https://github.com/FuturesJS/FuturesJS/tree/v3 --> 已弃用,带有 chainify 功能的新版本 (3) 尚未完成。看起来像是一个废弃的项目
  4. 我经常使用异步,我了解 waterfall 、系列和我经常使用的许多功能,我只是想将其重新安排为更简单的东西,以便在多个地方使用。我考虑如何“链接”它们,以便在其他文件中我可以使用相同的方法。

这就是为什么 async 不是我期望的答案的原因。

考虑会计问题,如果有一笔总额为 1200 美元的卖出交易,首先我必须将 1200 美元放入 Assets :现金账簿(借方),然后我必须将 1200 美元放入收入账簿(贷方)。可以用异步吗?是的当然。它看起来像这样:

async.series([
function(callback){
bookLibrary.debit('cash', 1200, callback);
},
function(callback){
bookLibrary.credit('income', 1200, callback);
}
]);

所以我想通过链接它们来使其更简单、更容易阅读,如下所示:

bookLibrary.debit('cash', 1200).credit('income', 1200)

最佳答案

首先,要链接一堆函数,您需要将它们配置为公共(public)对象上的方法。然后,每个方法都可以返回该对象,因此返回结果就是该对象,并且可以在该对象上调用下一个方法。

所以,要做这样的事情:

a().b().c();

您需要 a() 来返回一个具有 b() 方法作为属性的对象。并且,类似地,您需要 a().b() 来返回一个具有 c() 作为属性的对象。这通常称为流畅界面。对于同步方法来说,这本身就非常简单。这正是 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 会让这变得容易得多。以下是不使用 Promise 的实现的总体思路(未经测试):

为了简化异步操作的示例,让 a() 执行 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,那么事情会变得更简单:

所有异步操作(例如 firstAsyncOperationsecondAsyncOperation)都会返回一个 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
});

关于javascript - 如何在node.js中创建异步方法链?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41177879/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com