Question

I've read that is bad practice to mix synchronous and asynchronous operations in a function (e.g. http://nodejs.org/api/process.html#process_process_nexttick_callback).

Now i want to iterate a array of documents which i want to save in the database. Before the save begins, i need to validate all documents by step. A specific validator can be created later outside from the api.

The validate function can be completly synchronous (simple checking fields if they are valid like doc.sum > 10) but also asynchronous (if i need to get and validate a dependency document).

With the async library (https://github.com/caolan/async) i have something like this:

function validateAll(docs) {
    async.eachSeries(docs, function (doc, callback) {
        var async = false;
        validate(doc, function () {
            if (async) {
                callback();
            } else {
                process.nextTick(function () {
                    callback();
                });
            }
        });

        async = true;
    });
}

function validate(doc, callback) {
    if (doc.sum < 10) {
        return callback(new Error("Invalid sum"));
    }

    if (doc.otherDocumentId) {
        validateOtherDocFromDbAsync(doc.otherDocumentId, callback); // collection.find() or something
    } else {
        callback();
    }
}

In this example, i set the iteration callback on the next tick to avoid a "Maximum call stack size exceeded" error if many callbacks are called synchronously.

I have also thought to create validateSync and validateAsync functions to exactly define what they do.

Is this a bad practice? How would you design the api with this example?

Was it helpful?

Solution

Is this a bad practice?

Yes. http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony

How would you design the api with this example?

Instead of passing a callback to validate that handles whether it was called asynchronously or not, you should just make the validate function always asynchronous:

function validateAll(docs) {
    async.eachSeries(docs, validate);
}

function validate(doc, callback) {
    if (doc.sum < 10) {
        process.nextTick(function () {
            callback(new Error("Invalid sum"));
        });
    } else if (doc.otherDocumentId) {
        validateOtherDocFromDbAsync(doc.otherDocumentId, callback); // collection.find() or something
    } else {
        process.nextTick(callback);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top