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

丹尼·休

我想在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,然后CB可以无限制地重新排列链的顺序。这是我被搜索到的内容:

  1. 在node.js中创建链接方法?,->这是关于这个主题的先前的问题,非常古老,也不是异步的
  2. http://www.dustindiaz.com/async-method-queues/- >取决于jquery,客户端脚本,不是节点,不是异步
  3. https://github.com/FuturesJS/FuturesJS/tree/v3- >已过时,具有链化功能的较新版本(3)尚未完成。看起来像一个废弃的项目
  4. 经常使用异步,我了解瀑布,序列以及我经常使用的许多功能,我只想将其重新排列为更易于在多个地方使用的东西。我考虑如何“链接”它们,以便在其他文件中可以使用相同的方法。

这就是我为什么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)
jfriend00

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

因此,要做这样的事情:

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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在js中创建对象链

来自分类Dev

如何在Node js中创建图像?

来自分类Dev

如何在node.js中创建自定义异步函数?

来自分类Dev

如何在Node.JS中编写异步While循环

来自分类Dev

如何在Node.js中处理异步函数

来自分类Dev

如何在Node.js中处理异步函数

来自分类Dev

如何在节点js中创建异步回调?

来自分类Dev

如何在node.js中创建自己的脚本

来自分类Dev

如何在Node.js中创建双工流?

来自分类Dev

如何在canvas Node.js中创建渐变文本?

来自分类Dev

如何在Node.js中创建模型

来自分类Dev

如何在 WebStorm 中为 Node.js 创建项目?

来自分类Dev

如何在Node JS中打印对象

来自分类Dev

如何在node.js中搜索?

来自分类Dev

如何在Node JS中执行forloop

来自分类Dev

如何在 Node js 中添加会话

来自分类Dev

如何在for循环内编写node.js异步?

来自分类Dev

如何在Node JS中将异步转换为同步

来自分类Dev

如何在Node.js中使用异步映射系列?

来自分类Dev

如何在node.js中使此功能异步

来自分类Dev

如何在异步 Node.JS 中使用 MySQL

来自分类Dev

如何在Node.js模块中监视类方法

来自分类Dev

如何在Node.js模块中监视类方法

来自分类Dev

如何在node.js服务中调用POST方法?

来自分类Dev

如何在 Node.js 中对 MongoDB 使用 populate 方法?

来自分类Dev

如何在javascript或node中使其异步?

来自分类Dev

如何在javascript或node中使其异步?

来自分类Dev

如何在Node.js和MongoDb中的javascript中混合同步和异步代码

来自分类Dev

如何在Node.js模块中处理异步回调?