async waterfall步骤出错后的重试

来源:互联网 发布:淘宝网是如何盈利的 编辑:程序博客网 时间:2024/05/16 18:27

async给nodejs开发者们提供了很好的异步转同步的方法, 其中就以waterfall的应用最为广泛,waterfall的典型用法如下:

var async = require("async");async.waterfall([//step1function (cb) {    console.log("step1");    cb(null);},//step2function (cb) {    console.log("step2");    cb(null);},//step3function (cb) {    console.log("step3");    cb(null);}],function (e) {    console.log("complete, ", e);});

这段代码以可控顺序输出:

step1step2step3complete

但是有时候我们有这种需求:当step2执行出错时,我想重试最多两次step2,如果还出错,才跳到complete,而不是一出错就直接跳到complete。对于这种需求我是这么处理的:

var async = require("async");var retrystep = 0;async.waterfall([//step1function (cb) {    console.log("step1");    cb(null);},//step2// 首先需要给step2函数命名,不能是匿名函数function step2(cb) {    console.log("step2, retry=", retrystep);    //这里执行实际的逻辑过程,返回result    var result = false;// do_something();    //如果result错误,且重试次数小于3次,则继续执行step2    if (!result && retrystep < 2) {        //记录下增加的重试次数        retrystep++;        //再次执行step2,注意要带上参数cb        step2(cb);    }    else {        //如果执行正确就下一步        if (result) {            cb(null);        }        //否则就直接跳到结束complete        else {            cb("step2 error");        }    }},//step3function (cb) {    console.log("step3");    cb(null);}],//completefunction (e) {    console.log("complete, ", e);});

这段代码输出:

step1step2, retry= 0step2, retry= 1step2, retry= 2complete,  step2 error

step2执行了3次,这是重试自己这一步骤的情况,但是如果我重试上一步骤怎么办呢?根据上面的方法,我们很自然想到在step2中调用step1函数,如下:

var async = require("async");var retrystep = 0;async.waterfall([//step1function step1(cb) {    console.log("step1");    cb(null);},//step2// 首先需要给step2函数命名,不能是匿名函数function step2(cb) {    console.log("step2, retry=", retrystep);    //这里执行实际的逻辑过程,返回result    var result = false;// do_something();    //如果result错误,且重试次数小于3次,则继续执行step2    if (!result && retrystep < 2) {        //记录下增加的重试次数        retrystep++;        //再次执行step2,注意要带上参数cb        step1(cb);    }    else {        //如果执行正确就下一步        if (result) {            cb(null);        }        //否则就直接跳到结束complete        else {            cb("step2 error");        }    }},//step3function (cb) {    console.log("step3");    cb(null);}],//completefunction (e) {    console.log("complete, ", e);});

但是这段代码是有问题的,首先step2函数里面是调用不到step1函数的,其次调用step1的参数cb并不是step1的参数,所以要解决这个问题,我们就要设法在step2里面可以得到step1和其参数,我是这么实现的:

var async = require("async");var retrystep = 0;var state = {};async.waterfall([//step1//同样step1需要命名function step1(cb) {    //这里记录下step1函数名和参数,保存在state中,用于在每个步骤中传递    state.step1 = step1;    state.step1cb = cb;    console.log("step1, retry=", retrystep);    cb(null);},//step2// 首先需要给step2函数命名,不能是匿名函数function step2(cb) {    console.log("step2, retry=", retrystep);    //这里执行实际的逻辑过程,返回result    var result = false; // do_something();    //如果result错误,且重试次数小于3次,则再次从step1执行起    if (!result && retrystep < 2) {        //记录下增加的重试次数        retrystep++;        //再次从step1执行起来,同样要带上保存的参数step1cb        state.step1(state.step1cb);    }    else {        //如果执行正确就下一步        if (result) {            cb(null);        }        //否则就直接跳到结束complete        else {            cb("step2 error");        }    }},//step3function (cb) {    console.log("step3");    cb(null);}],//completefunction (e) {    console.log("complete, ", e);});

以上这段代码输出如下:

step1, retry= 0step2, retry= 0step1, retry= 1step2, retry= 1step1, retry= 2step2, retry= 2complete,  step2 error
step1和step2各执行了3次。

0 0
原创粉丝点击