Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to write asynchronous Node.js code "cleaner"?

While coding in Node.js, I encountered many situations when it is so hard to implement some elaborated logic mixed with database queries (I/O).

Consider an example written in python. We need to iterate over an array of values, for each value we query the database, then, based on the results, we need to compute the average.

def foo:
  a = [1, 2, 3, 4, 5]
  result = 0
  for i in a:
    record = find_from_db(i) # I/O operation
    if not record:
      raise Error('No record exist for %d' % i)
    result += record.value

  return result / len(a)

The same task in Node.js

function foo(callback) {
  var a = [1, 2, 3, 4, 5];
  var result = 0;
  var itemProcessed = 0;
  var error;
  function final() {
    if (itemProcessed == a.length) {
      if (error) {
        callback(error);
      } else {
        callback(null, result / a.length);
      }
    }
  }
  a.forEach(function(i) {
    // I/O operation
    findFromDb(function(err, record) {
      itemProcessed++;
      if (err) {
        error = err;
      } else if (!record) {
        error = 'No record exist for ' + i;
      } else {
        result += record.value;
      }
      final();
    });
  });
}

You can see that such code much harder to write/read, and it is more prone to errors. My questions:

  1. Is there a way to make above Node.js code cleaner?
  2. Imagine more sophisticated logic. For example, when we obtained a record from the db, we might need do another db query based on some conditions. In Node.js that becomes a nightmare. What are common patterns for dealing with such tasks?
  3. Based on your experience, does the performance gain deserves the productivity loss when you code with Node.js?
  4. Is there other asynchronous I/O framework/language that is easier to work with?
like image 985
ashim Avatar asked Dec 06 '22 00:12

ashim


1 Answers

To answer your questions:

  1. There are libraries such as async which provide a variety of solutions for common scenarios when working with asynchronous tasks. For "callback hell" concerns, there are many ways to avoid that as well, including (but not limited to) naming your functions and pulling them out, modularizing your code, and using promises.

  2. More or less what you currently have is a fairly common pattern: having counter and function index variables with an array of functions to call. Again, async can help here because it reduces this kind of boilerplate that you will probably find yourself repeating often. async currently doesn't have methods that really allow for skipping individual tasks, but you could easily do this yourself if you are writing the boilerplate (just increment the function index variable by 2 for example).

  3. From my own experience, if you properly design your javascript code with asynchronous in mind and use a lot of tools like async, you will find it easier to develop with node. Writing for asynchronous vs synchronous in node is typically always going to be more complicated (although less so with generators, fibers, etc. as compared to callbacks/promises).

  4. I personally think that deciding on a language based upon that single aspect is not worthwhile. You have to consider much much more than just the design of the language, for example the size of the community, availability of third party libraries, performance, technical support options, ease of code debugging, etc.

like image 53
mscdex Avatar answered Jan 13 '23 09:01

mscdex