Node.js函数流

时间:2015-12-13 05:01:13

标签: javascript node.js

当我收到请求时,我希望它生成一个4个字符的代码,然后检查它是否已存在于数据库中。如果是,则生成新代码。如果没有,请添加并继续。这就是我到目前为止所做的:

var code = "";
var codeFree = false;
while (! codeFree) {
    var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    var code = "";
    for (var i = 0; i < 4; i++) {
        var rand = Math.floor(Math.random() * chars.length);
        console.log(rand);
        code += chars.charAt(rand);
    }
    console.log("Code: %s generated.", code);

    client.execute("select * from codes where code=" + code, function(err, result) {
        if (! err) {
            if (result.rows.length > 0) {
                codeFree = false;
            } else {
                codeFree = true;
            }
        } else {
            console.log('DB ERR: %s', err);
        }
        console.log(codeFree);
    });
    console.log('here');
}

这几乎没有我想做的事情。我怎么能处理这样的事情?

2 个答案:

答案 0 :(得分:2)

您正在执行异步任务。

当你的程序中有异步任务时,你需要有一个回调函数,它将以所需的值作为参数调用。

当你找到免费代码时,你调用该函数并将代码作为参数传递,否则,再次调用 <img src=assets/img/Guild/0000$logo/$logoColor.png class=\"avatar img-responsive\" style=\"margin: 0 auto; position: absolute; z-index: 10;\"> <img src=assets/img/Guild/0000$logoBG/$logoBGColor.png class=\"avatar img-responsive\" style=\"margin: 0 auto; position: absolute; z-index: -1;\"> 函数并将相同的回调传递给它。虽然您可能会考虑发生错误的情况。如果您的db调用失败,则永远不会调用您的回调。最好使用getFreeCode / throw机制或将另一个参数传递给您的回调。

你可以通过这种方式实现你需要做的事情:

catch

答案 1 :(得分:2)

我建议你研究两种替代方法来帮助处理异步代码。

  1. 节点生成器功能使用&#39; yield&#39;关键字
  2. 使用生成器需要使用--harmony标志运行最新版本的节点。我推荐生成器的原因是因为您可以编写按预期方式流动的代码。

    var x = yield asyncFunction();
    console.log('x = ' + x);
    

    在记录x之前,前面的代码将获得x的值。

    在没有让出console.log的情况下,在async函数完成获取x的值之前会写出x。

    您的代码可能看起来像生成器:

    var client = {
        execute: function (query) {
            var timesRan = 0;
            var result = [];
            return function () {
                return setTimeout(function () {
                    result = ++timesRan < 4 ? ['length_will_be_1'] : [];
                    return result;
                },1);
            };
        }
    };
    
    function* checkCode () {
        var code;
        var codeFree = false;
        while(!codeFree) {
        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        code = "";
        for (var i = 0; i < 4; i++) {
          var rand = Math.floor(Math.random() * chars.length);
          console.log(rand);
          code += chars.charAt(rand);
        }
        console.log("Code: %s generated.", code);
    
        try {
            var result = yield client.execute("select * from codes where code="+code);
          codeFree = result.rows.length > 0 ? false : true;
          }catch(e) {
            console.log('DB ERR: %s', err);
          } finally {
            console.log(codeFree);
          }
    
        console.log('here');
      }
    }
    
    checkCode().next();
    

    您将离开客户端对象。我只是添加了一个用于伪造异步调用的工作示例。

    如果你必须使用旧版本的节点或不喜欢yield语法,那么promises可能是一个值得的选择。

    有许多承诺库。我推荐promises的原因是你可以编写符合预期的代码:

    asyncGetX()
    .then(function (x) {
        console.log('x: ' + x);
    });
    

    在记录x之前,前面的代码将获得x的值。

    它还允许您链接异步函数并按顺序运行它们:

    asyncFunction1()
    .then(function (result) {
        return asyncFunction2(result)
    })
    .then(function (x) { /* <-- x is the return value from asyncFunction2 which used the result value of asyncFunction1 */
        console.log('x: ' + x);
    });
    

    您的代码看起来像是&#39; q&#39;承诺图书馆:

    var Q = require('q');
    
    var client = {
        timesRan: 0,
        execute: function (query, callback) {
            var self = this;
            var result = {};
            setTimeout(function () {
                console.log('self.timesRan: ' + self.timesRan);
                    result.rows = ++self.timesRan < 4 ? ['length = 1'] : [];
                    callback(null, result);
            },1);
        }
    };
    
    function checkCode () {
        var deferred = Q.defer();
        var codeFree = false;
      var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      var code = "";
      for (var i = 0; i < 4; i++) {
        var rand = Math.floor(Math.random() * chars.length);
        console.log('rand: %s', rand);
        code += chars.charAt(rand);
      }
      console.log("Code: %s generated.", code);
    
        client.execute("select * from codes where code="+code, function(err, result) {
            console.log('err: '+err+', result: ' + JSON.stringify(result));
            console.log('result.rows.length: ' + result.rows.length);
        if(!err) {
          if(result.rows.length > 0) {
            codeFree = false;
            console.log('result.rows: %s, codeFree: %s', result.rows, codeFree);
            checkCode();
          } else {
            codeFree = true;
            console.log('line 36: codeFree: ' + codeFree);
            deferred.resolve(code);
          }
        }else {
          console.log('DB ERR: %s', err);
              deferred.reject(err);
        }
        console.log(codeFree);
      });
      console.log('waiting for promise');
    
      return deferred.promise;
    }
    
    checkCode()
    .then(function (code) {
        console.log('success with code: ' + code);
    })
    .fail(function(err) {
      console.log('failure, err: ' + err);
    });
    

    此处也省略了客户端对象。我只是添加了一个用于伪造异步调用的工作示例。

    Promise和generator绝对需要一段时间才能习惯。这是值得的,因为它们使代码最终比使用嵌套回调编写的代码更容易理解。