There are a few design patterns you can use in node.js to run sequential asynchronous operations. In all of them, you cannot run a tight loop waiting for something to happen - you have to let the single Javascript thread in node.js run and give it as many cycles as possible.
Manual Iteration
Put the code for an iteration in a local function (I usually call it next()
) and then when one iteration calls its last completion function, you can call next()
again to start the next iteration. You can finish the operation either by testing some condition and not calling next()
if things are done or the first lines of next()
can test to see if you're done.
See the code example below for how your code would look like with manual iteration.
Sequence promises
If you use promises for your asynchronous operations, then you can let chained promises do all your sequencing for you as in p().then(f1).then(f2).then(f3)
. You can see an example of that in this answer: Promises like async.each.
Use the Async Module
The Async module supports a number of async management functions. Many find it very useful - others would prefer to use promises to solve similar problems. In any case, it has a number of different functions for sequencing. For example if you wanted to iterate an array asynchronously, you would use something like this:
async.eachSeries(hugeArray, function iterator(item, callback) {
if (inCache(item)) {
callback(null, cache[item]); // if many items are cached, you'll overflow
} else {
doSomeIO(item, callback);
}
}, function done() {
//...
});
Here's a version of your code that does the manual iteration using a custom next()
iteration function.
function runQuery(callback) {
mysql.getConnection(function(err, connection) {
if (err) {
connection.release();
callback(err);
return;
}
var array = [];
var count = 10;
var index = 0;
function next() {
if (index++ < count) {
array.push([index, 'master']);
console.log('100-elements');
connection.beginTransaction(function(err) {
if (err) {
// can't throw here in an async function
// use callback to communicate error
callback(err);
return;
}
var query = "insert into users(username, password) values ?";
connection.query(query, [array], function(err, rows) {
if (!err) {
//commit start
connection.commit(function() {
if (err) {
console.error(err);
connection.rollback(function() {
console.error('rollback error');
callback(err);
return;
});
} else {
console.log("Commit");
// now do the next iteration
next();
} // if err
}); //commit end
} else {
console.log(err);
connection.rollback(function() {
callback(err);
return;
});
} // if
});
});
}
}
});
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…