Skip to content
Seth Yuan edited this page Nov 1, 2013 · 11 revisions

Firstly, if you haven't read the Tutorial, now is the time.

In this guide, you will learn about some important things when using asyncflow.

Async functions should follow Node.js convention

Put your callback as the last argument of the function. Like:

function myAsyncFunc(arg1, arg2, callback) {
 ...
}

If your functions are not written in this convention, you will have to write wrappers for them manually, like:

function strangeFunc(callback, arg) {
  ...
}

function shinyStrangeFunc(arg, callback) {
  strangeFunc(callback, arg);
}

Also, the first argument of your function callback should be an error object, if you have multiple arguments; or anything if you have only 1 argument. e.g.

function myFunc(callback) {
  // callback(err, ...) or
  // callback(x)
}

Wrap only asynchronous functions

Now, the whole reason you wrap a function with flow.wrap is so you can call it in a synchronous way within a flow block. So would you want to wrap a synchronous function?

DON'T DO THIS:

var flow = require("asyncflow");

function sum(a, b) {
  return a + b;
}

var sum$ = flow.wrap(sum);

flow(function() {
  var result = sum$(1, 2).wait();
  ...
});

Instead, you just do this:

var flow = require("asyncflow");

function sum(a, b) {
  return a + b;
}

flow(function() {
  var result = sum(1, 2);
  ...
});

It is really bad for health to wrap a synchronous function, you've been warned!!! That way said, if you really want to convert a synchronous function into a asynchronous one, you can do it with a call to process.nextTick.

function sum(a, b, callback) {
  process.nextTick(function() {
    callback(a + b);
  });
}

Flow blocks are asynchronous

Bear in mind that a flow block is just a asyncflow call.

var flow = require("asyncflow");

// This flow block is just an asynchronous call like any others.
flow(function() {
  ...
});

Don't put non-wrapped asynchronous calls in a flow block

Flow block cannot track an non-wrapped asynchronous call, so you won't be able to achieve the synchronous style desired in a flow block. In short, don't do it.

DON'T DO THIS:

var flow = require("asyncflow");
var fs = require("fs");

var readFile = flow.wrap(fs.readFile);

flow(function() {
  fs.exists("file.txt", function(exists) {
    if (exists) {
      var data = readFile("file.txt").wait();
      ...
    }
  });
});

Instead, do this:

var flow = require("asyncflow");
var fs = require("fs");

var exists = flow.wrap(fs.exists);
var readFile = flow.wrap(fs.readFile);

flow(function() {
  if (exists("file.txt").wait()) {
    var data = readFile("file.txt").wait();
    ...
  }
});

or do this:

var flow = require("asyncflow");
var fs = require("fs");

var exists = flow.wrap(fs.exists);
var readFile = flow.wrap(fs.readFile);

function checkAndRead() {
  if (exists("file.txt").wait()) {
    var data = readFile("file.txt").wait();
    ...
  }
}

flow(function() {
  checkAndRead();
});

That is, only put synchronous functions calls and wrapped function calls inside a flow block.

Don't use wrapped functions outside of a flow block

I mean, it's meaningless, plus it causes exceptions to throw (obviously).

Exceptions thrown in asynchronous calls are evil

While this is not specific to asyncflow, but to all of Node.js, I feel I have to mention it here.

Exceptions thrown in an asynchronous call are not able to be caught, so they should be avoided. e.g.

function errorFunction(cb) {
  setTimeout(function() {
    throw new Error("custom error");
    cb(null);
  }, 10);
}

The exception thrown in the code above cannot be caught by a try catch block. The best you can do, is to rewrite it like this:

function errorFunction(cb) {
  setTimeout(function() {
    try {
      throw new Error("custom error");
      cb(null);
    } catch (e) {
      cb(e);
    }
  }, 10);
}

Collection functions and callback

Consider:

var mapped = [1, 2, 3].map(function(v) {
  return v * 2;
});

If you want to use the parallel version of map, you will have to write this:

var flow = require("asyncflow");

flow(function() {
  var mapped = flow.wrapped.map([1, 2, 3], flow.wrap(function(v, i, a, cb) {
    process.nextTick(function() {
      cb(v * 2);
    });
  })).wait();
});

Notice that we had to convert the mapping function into an asynchronous version, and, we also had to specify the complete argument list for the mapping function. This is because the callback we added has to be the last argument and the mapping function is already being called with 3 arguments.

A way to avoid specifying the whole argument list, is to use function's arguments manipulation:

var flow = require("asyncflow");

flow(function() {
  var mapped = flow.wrapped.map([1, 2, 3], flow.wrap(function(v) {
    var cb = arguments[arguments.length - 1];
    process.nextTick(function() {
      cb(v * 2);
    });
  })).wait();
});
Clone this wiki locally