jmar777 / suspend

Callback-free control flow for Node using ES6 generators.
548 stars 22 forks source link

Support calling fork()(err, val) manually #19

Closed notcome closed 10 years ago

notcome commented 10 years ago

Sometime it is required to call fork()(err, val) immediately. For example, if I need asynchronously load a directory and all sub-directories:

function loadDirectory (path, cb) {
  suspend.run(function *() {
    let list = {};
    let files = yield fs.readdir(path, resume());
    let paths = map(files, function (name) { return path + '/' + name; });
    let stats = yield async.map(paths, fs.stat, resume());

    for (let i = 0; i < files.length; i ++)
      if (stats[i].isDirectory())
        loadDirectory(paths[i], suspend.fork());
      else
        suspend.fork()(null, files[i]);

    let result = yield suspend.join();
    for (let i = 0; i < files.length; i ++)
      list[files[i]] = result[i];
    return list;
  }, function (err, list) { cb(err, list); });
}

Though we could put the file/directory detecting code in loadDirectory (it is definitely better, making the programming stronger to invalid input), it would be a little confusing that suspend weirdly consumes fork values.

A more crazy example:

suspend.run(function*() {
  for (var i = 0; i < 5; i ++)
    fork()(null, i);
});

In the original implementation, only the last item will be in the array.

jmar777 commented 10 years ago

@notcome Thanks so much for the pull request! Stupid mistake on my part - the bug only manifests itself if you resolve a fork() prior to having initiated all the forks that you need (which almost never happens unless you're resolving synchronously like you were). That was a great catch!