简体   繁体   English

Node.js功能流程

[英]Node.js Function Flow

When I get a request, I want it to generate a 4-character code, then check if it already exists in the database. 收到请求后,我希望它生成一个4个字符的代码,然后检查它是否已存在于数据库中。 If it does, then generate a new code. 如果是这样,则生成一个新代码。 If not, add it and move on. 如果没有,请添加并继续。 This is what I have so far: 这是我到目前为止的内容:

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');
}

This does not do nearly what I want it to do. 这几乎不能满足我的要求。 How can I handle something like this? 我该如何处理这样的事情?

You are doing an async task. 您正在执行异步任务。

When you have an asyncronous task inside your procedure, you need to have a callback function which is going to be called with the desired value as its argument. 当您的过程中有一个异步任务时,您需要一个回调函数,该函数将使用所需的值作为其参数进行调用。

When you found the free code, you call the function and passing the code as its argument, otherwise, you call the getFreeCode function again and passing the same callback to it. 找到免费代码后,将调用该函数并将代码作为其参数传递,否则,将再次调用getFreeCode函数并将相同的回调传递给它。 Although you might consider cases when an error happens. 尽管您可能会考虑发生错误的情况。 If your the db call fails, your callback would never get called. 如果您的db调用失败,则将永远不会调用您的回调。 It is better to use a throw / catch mechanism or passing another argument for error to your callback. 最好使用throw / catch机制或将另一个错误参数传递给回调。

You can achieve what you need to do by doing it this way: 您可以通过以下方式完成您需要做的事情:

function getFreeCode(callback) {
    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) {
          getFreeCode(callback);
        } else {
          callback(code);
        }
      }else {
        console.log('DB ERR: %s', err);
      }
      console.log(codeFree);
    });
    console.log('here');
}




// in your main:

getFreeCode(function (code) {
    console.log(' this code was free: ' + code)
})

I recommend you look into two alternatives to help deal with asynchronous code. 我建议您研究两种替代方法来帮助处理异步代码。

  1. node generator functions using the 'yield' keyword 使用'yield'关键字的节点生成器功能
  2. promises 诺言

Using generators requires running a recent version of node with the --harmony flag. 使用生成器需要运行带有--harmony标志的最新版本的节点。 The reason I recommend generators is because you can write code that flows the way you expect. 我之所以推荐生成器,是因为您可以编写符合预期方式的代码。

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

The previous code will get the value of x before logging x. 先前的代码将在记录x之前获取x的值。

Without yielding the console.log would write out x before the async function was finished getting the value for x. 如果不屈服console.log,它将在异步函数完成获取x的值之前写出x。

Your code could look like this with generators: 使用生成器,您的代码可能看起来像这样:

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();

You would leave off the client object. 您将放弃客户端对象。 I only added that to make a working example that fakes an async call. 我只是添加了一个假冒异步调用的工作示例。

If you have to use an older version of node or do not like the yield syntax then promises could be a worthy option. 如果您必须使用旧版本的节点或不喜欢yield语法,那么promises是一个值得选择的选择。

There are many promise libraries. 有许多承诺库。 The reason I recommend promises is that you can write code that flows the way you expect: 我建议承诺的原因是您可以编写符合预期方式的代码:

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

The previous code will get the value of x before logging x. 先前的代码将在记录x之前获取x的值。

It also lets you chain async functions and runs them in order: 它还允许您链接异步函数并按顺序运行它们:

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);
});

Your code could look like this with the 'q' promise library: 使用“ q”承诺库,您的代码可能如下所示:

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);
});

Also omit the client object here. 在此也忽略客户端对象。 I only added that to make a working example that fakes an async call. 我只是添加了一个假冒异步调用的工作示例。

Promises and generators definitely take some time to get used to. 承诺和生成器肯定需要一些时间来习惯。 It's worth it because they make the code a lot easier to follow in the end than code written with nested callbacks. 这样做是值得的,因为它们使代码最终比嵌套回调编写的代码更容易遵循。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM