Refactor a non-blocking js node do..while
I am writing api in node.js. The first webservice endpoint - /create
- creates a new db entry with a randomized 6 character hash, very similar to the .ly hash bit.
After doing something like this in PHP, I wrote a loop do..while
that generates a random string and checks my mysql db (using node-mysql) to make sure it is free. I also have a counter so I can crash after x
iterations if needed.
var i = 0;
var alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
var hash = null;
var success = false;
do {
// generate a random hash by shuffling the alphabet,
// joining it and getting 6 chars
hash = alphabet.sort(function(){
return 0.5 - Math.random();
}).join('').substr(0,6);
console.log(i + ': checking hash ' + hash);
// see if it exists in the db
db.query("SELECT hash FROM trips WHERE hash = " + hash, function(err, results){
if(results.length == 0) {
// the hash is free to use :)
success = true;
} else {
// the hash is already taken :(
success = false;
}
});
// increment the counter
i++;
} while(success === false && i < 10);
Currently I only have one hash in my db ( abcdef
), but the loop reaches ten and doesn't work because it thinks every new hash is already present.
I'm pretty sure it has to do with the non-blocking nature of node.js. This is obviously a "good thing", but in my case, I need the loop to block until the request returns.
I'm sure I can hack this by doing something like:
var q = db.query(...);
But I know this is throwing away the main feature of node.js.
Is there a code template for this kind of need?
source to share
I'm pretty sure this has to do with the non-blocking nature of node.js.
Yes.
This is obviously a good thing, but in my case, I need the loop to block until the request returns.
No, you certainly don't want to do that.
Declare an asynchronous approach. Working with callbacks:
function generateHash(onSuccess, onError, retryCount) {
// generate a random hash by shuffling the alphabet,
// joining it and getting 6 chars
var hash = alphabet.sort(function(){
return 0.5 - Math.random();
}).join('').substr(0,6);
// see if it exists in the db
db.query(
"SELECT hash FROM trips WHERE hash = '" + hash + "'",
function(err, results){
if (results.length == 0) {
// the hash is free to use :)
onSuccess(hash);
} else {
// the hash is already taken :(
if (retryCount > 1) {
generateHash(onSuccess, onError, retryCount - 1);
} else {
onError();
}
}
}
});
}
generateHash(
function(hash) { console.log('Success! New hash created: ' + hash); },
function() { console.log('Error! retry limit reached'); },
6
);
source to share
var i=0;
function generateHash(callback) {
// generate a random hash by shuffling the alphabet,
// joining it and getting 6 chars
hash = alphabet.sort(function(){
return 0.5 - Math.random();
}).join('').substr(0,6);
console.log(i + ': checking hash ' + hash);
// see if it exists in the db
db.query("SELECT hash FROM trips WHERE hash = " + hash, function(err, results){
if(results.length == 0) {
// the hash is free to use :)
callback(null, hash);
} else {
// increment the counter
i++;
if (i < 10)
generateHash(callback); //another attempt
else
callback('error'); // return result
}
});
}
source to share