Node.js函数stream程

当我收到请求时,我想让它生成一个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'); } 

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

你正在做一个asynchronous任务。

当你的程序中有一个asynchronous的任务时,你需要有一个callback函数,这个callback函数将以所需的值作为参数被调用。

当你find空闲的代码时,你调用这个函数并把代码作为它的parameter passing,否则你再次调用getFreeCode函数并把相同的callback传递给它。 虽然你可能会考虑发生错误的情况。 如果你的数据库调用失败,你的callback将永远不会被调用。 最好是使用throw / catch机制或者将错误传递给你的callback函数。

你可以通过这样做来实现你需要做的事情:

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

我build议你看看两种方法来帮助处理asynchronous代码。

  1. 节点生成器函数使用“yield”关键字
  2. 许诺

使用生成器需要使用–harmony标志运行最近版本的节点。 我推荐使用生成器的原因是因为您可以编写按您期望的方式stream动的代码。

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

前面的代码会在loggingx之前得到x的值。

没有yielding console.log会写出asynchronous函数完成之前得到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(); 

您将离开客户端对象。 我只是补充说,做一个工作的例子,虚假的asynchronous电话。

如果你必须使用旧版本的节点,或者不喜欢yield语法,那么承诺可能是一个有价值的select。

有许多承诺库。 我推荐的承诺的原因是,你可以编写你期望的代码:

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

前面的代码会在loggingx之前得到x的值。

它还可以让你链接asynchronous函数,并按顺序运行它们:

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

你的代码可能看起来像这个'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); }); 

此处也省略客户端对象。 我只是补充说,做一个工作的例子,虚假的asynchronous电话。

承诺和发电机肯定需要一些时间来习惯。 这是值得的,因为它们使代码比嵌套callback编写代码更容易遵循。