-->

如何步骤代码转换为Async.JS(步骤=>瀑布,this.parallel)?(How to

2019-10-19 11:20发布

几年前,我与实验的NodeJS和发现“步骤”库清理我的一些代码,而漂亮。 当希望把这些代码是最新的,我注意到步数“红旗”。 (并非为一两年,只有32个提交等更新)

所以,我环顾四周,发现Async.js ,它有更多的功能和有效的维护。

看起来不错,一般。 但是,我开始尝试应用改造,用它来代替,并且可能不会采取正确的角度。

如果我读正确,步骤的核心功能似乎正是Async.JS会叫“瀑布”的格局 。 因此,在步骤你可以这样写:

Step(
    function firstStepNoArgs() {
        foo.asyncCall(this);
    },
    function secondStep(err, argFromFoo) {
        if (err) {
            handleError(err);
        }

        bar.asyncCall(argFromFoo, 1, this.parallel());
        baz.asyncCall(argFromFoo, 2, this.parallel());
    },
    function thirdStep(err, argFromBar, argFromBaz) {
        if (err) {
            handleError(err);
        }

        /* etc... */
    }
);

如果我不知道任何更好,我可能已经猜到你会做,在async.js像这样(未经测试,认为这是伪代码,我说的是我还没有真正追求的理论变化尚)

function thirdStep(argFromBar, argFromBaz) {
    /* etc... */
}

async.waterfall([
    function firstStepNoArgs(callback) {
        foo.asyncCall(callback);
    },
    function secondStep(argFromFoo, callback) {
        async.parallel([
            barResult: function(callback) {
                bar.asyncCall(parameterFromFoo, 1, callback);
            },
            bazResult: function(callback) {
                baz.asyncCall(parameterFromFoo, 2, callback);
            }
        ],
            function(err, result) {
                if (err) {
                    handleError(err);
                } else {
                    thirdStep(result.barResult, result.bazResult);
                }
            }
    }
],
   function(err, result) {
       if (err) {
           handleError(err);
       } else {
           /* no-op? just assume third-step runs? */
       }
   }
);

步骤是非常注重和顺序,我这里有点草案显示,它在适应越来越混乱。 我缺少的东西吗?

所以我的问题是 :什么是明确的步骤代码转换成Async.JS的正确方法? 还是我选择了错误的库升级到? 我不希望我的代码变得更丑,但我不想依赖,似乎有种“死”一库,无论是。 : - /

Answer 1:

按照要求,什么样的实现您与承诺做。 只需粘贴并运行,你应该明白我的意思。 牢记代码的上半部分是建立模拟功能,这样可以更好地沿着这是如何工作遵循。 有人可能会告诉我,我应该这样做的依据,这是我可以做的一样好。

var Q = require('q');

var foo ={},  bar ={}, baz = {};
//   let's mock up some of your objects with some asynch functions
//   using setTimeout for async completion
foo.asyncCall = function ( cb) {
    setTimeout(function(){ cb(null, 'promises'); },500);
};
bar.asyncCall = function ( arg1, arg2, cb) {
    setTimeout(function(){
        var result = arg1 + ' can be ' + arg2;
        cb(null, result);
    },1200);
};
//  going to add a will-always-fail function for example purposes
bar.asyncFailure = function (arg1, arg2, cb){
    setTimeout(function(){
        cb(new Error(arg1 +' offer decent error handling'), null);
    },2000);    // longer delay - simulate a timeout maybe
};

baz.asyncCall = function ( arg1, arg2, cb) {
    setTimeout(function(){
        var result = arg1 + ' are really ' + arg2;
        cb(null, result);
    },800);
};

//  set up promise-enbaled calls. Q.denodeify is an easy way to deal with any
//  standard node function with a final parameter being an (err,data) callback
//  If these are your own functions, you can also create your own promises, but
//  Q.nodeify is probably the fastest way to adapt existing code.

bar.promiseFailure = Q.denodeify(bar.asyncFailure);
bar.promiseCall = Q.denodeify(bar.asyncCall);
baz.promiseCall = Q.denodeify(baz.asyncCall);

//  this is your wrap up call ('thirdStep' in your code)
function allTogetherNow(arg1, arg2) {
    console.log(arg1 +'\n' + arg2);
};

// now we can have some fun
//  an example that will run to completion normally
//  Q.ninvoke is sort of a 'one-time' denodeify, it invokes a node-style function
//  and returns a promise

function example(){
    Q.ninvoke(foo,'asyncCall')
        .then( function (x) {
            return [bar.promiseCall(x, 'confusing at first'),
                    baz.promiseCall(x, 'awesome after that')]
        })
        .spread(allTogetherNow)
        .fail(function(e){console.log('Had an error')})
        .finally(function(){console.log('Calling no matter what from example')});

};
// sometimes things aren't entirely fun though, and there can be an error
function example2(){
    Q.ninvoke(foo,'asyncCall')
        .then( function (x) {
            return [bar.promiseFailure(x, 'confusing at first'),
                    baz.promiseCall(x, 'awesome after that')]
        })
        .spread(allTogetherNow)
        .fail(function(e){console.log(e)})
        .finally(function(){console.log('Calling no matter what from example2')});
};

example();
example2();

对于那些不希望打扰运行它,发出的输出是:

promises can be confusing at first
promises are really awesome after that
Calling no matter what from example
[Error: promises offer decent error handling]
Calling no matter what from example2


Answer 2:

小心你的回调,在这里。 回调签名是:

callback(err, arg1, arg2 ...)

所以,如果你foo.asyncCall是与调用它:

callback(result1, result2)

然后,整个异步会莫名其妙的从该点失败。 成功的正确的回调应该用一个空,如启动

callback(null, result1, result2)

下面是更正后的代码:

function thirdStep(argFromBar, argFromBaz, callback) {
    /* etc... */
    callback(null, result);
}

async.waterfall([
    function firstStepNoArgs(callback) {

        // error callback("failed").  First args is not null means failed
        // in case of error, it just goes straight to function(err, result)

        foo.asyncCall(callback);
    },
    function secondStep(argFromFoo, callback) {

        // argFromFoo come from previous callback (in this case, result1)

        async.parallel([
            barResult: function(callback) {
                bar.asyncCall(parameterFromFoo, 1, callback);
            },
            bazResult: function(callback) {
                baz.asyncCall(parameterFromFoo, 2, callback);
            }
        ],
            function(err, result) {
                if (err) {
                    // in case of error you should do callback(error),
                    // this callback is from secondStep(argFromFoo, callback).

                    // this will pass to final function(err, result).

                    handleError(err);

                } else {

                    // you need to do callback(null) inside thirdStep
                    // if callback is not called, the waterfall won't complete

                    thirdStep(result.barResult, result.bazResult, callback);
                }
            }
    }
],
   function(err, result) {
       if (err) {
           handleError(err);
       } else {

           // everything is executed correctly, 
           // if any step failed it will gone to err.

       }
   }
);


文章来源: How to convert Step code to Async.JS (Step => waterfall, this.parallel)?