have a for loop with a dynamic value that could be small to big, I want to make sure one call to search is finished before the next one can start. how do I do that? I've read about process.nextTick and setImmediate but I'm unsure how to use either in this context.
function search(x) {
dns.resolve(x, function (err, addresses) {
if (!err) {
res.send("bad");
} else {
res.send("good");
}
});
}
for(a = 0; a < queries.length; a++) {
query = queries[a];
search(query);
}
There are a few libraries out there that can help you organize the execution of asynchronous code. Async is the one I use and it's eachSeries() is useful here:
function search(x,callback) {
dns.resolve(x, function (err, addresses) {
if (!err) {
res.send("bad");
} else {
res.send("good");
}
callback(err);
});
}
async.eachSeries(queries,
function(query,callback) {
search(query,callback);
},
function(err) {
if(err) {
console.log("we had an error");
}
}
);
Note that Async will call the final callback as soon as one of the iterations has an error so if you don't want to stop there, you'll need to call callback()
in the search()
instead of callback(err)
.
UPDATE (without using a library):
If you don't want to use a library, you could implement it yourself like this:
function searchInternal(queries, idx, callback) {
if(idx === queries.length) {
callback();
return;
}
dns.resolve(queries[idx], function (err, addresses) {
if (!err) {
res.send("bad");
} else {
res.send("good");
}
searchInternal(queries, idx+1, callback);
});
}
function searchAll(queries, callback) {
searchInternal(queries, 0, callback);
}
searchAll(queries, function() {
console.log("all done now");
});
Note, this code isn't tested, and probably isn't the best implementation, but thats why we use libraries.
I usually just use event emitters to make it all synchronous so I can still work within the asynchronous environment mindset. In my code below, whenever a DNS resolve gets finished, it produces an event that is listened to by the search function and lets it know to fire a new search. Plus, you get to learn how to create your own Event Emitters, which are awesome.
If you want to make it asynchronous for a certain size of the domain name array, you can create a denominator variable and use the modulus operator to send asynchronous in chunks and only fire a synchronous event(to clear the async buffer) whenever the modulus reaches 0.
// program that uses event emitters to create sync code in an async env
var dns = require('dns') //dns from core
var eventEmitter = require('events').EventEmitter //Event Emitter from core
var ee = new eventEmitter; //make an Event Emitter object
var queries = ['yahoo.com','google.com','james.com'];
ee.on('next', next_search); //create a listener for an event we define
// our listening function that executes on our defined 'next' event
function next_search() {
search(queries[a]);
if(queries.length == a) process.exit(0);
++a;
}
// the actual search function that uses DNS
function search(x) {
dns.resolve(x, function (err) {
if (!err) {
//res.send("bad");
console.log('bad: ' + x)
ee.emit('next')
} else {
//res.send("good");
console.log('good: ' + x)
ee.emit('next')
}
});
}
// global variable to keep track of our name queue length
var a = 0;
// kick it all off
next_search()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With