{"_id":"begin","_rev":"9-74b76d66a60c24ec200d3c5926d02888","name":"begin","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"begin","version":"0.1.0","author":{"name":"Ben Weaver","email":"ben@orangesoda.net"},"main":"./lib/begin","_id":"begin@0.1.0","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.8-1","_nodeVersion":"v0.4.1","dist":{"tarball":"https://registry.npmjs.org/begin/-/begin-0.1.0.tgz","shasum":"d7eec4d33bce872764cd0b6c7646452d1b9de016","integrity":"sha512-fyn6ae3MvkPf3E0uS5UnhwQQbdV9L+n4RQ7/jj3E8Vi3obHY7IZL2ougyFErEVlZ5tx7CbAKcicp+Xmk2mUZXw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD8jafYk21NQTEwBQG157AUHgtgr65TQKZXY9RBfBq/YAIhANqPPkTsCWovwrNGfve1zJdYhE35e1PGHPSrVzO12/km"}]}},"0.2.1":{"name":"begin","version":"0.2.1","description":"Asynchronous flow control for node.js and browsers","main":"./begin.js","scripts":{"test":"mocha --spec"},"repository":{"type":"git","url":"https://github.com/kloshih/begin.git"},"bugs":{"url":"https://github.com/kloshih/begin/issues"},"license":"BSD","keywords":["flow","control","async","asynchronous"],"author":{"name":"Lo Shih"},"devDependencies":{"chai":"^3.4.0","grunt":"^0.4.5","grunt-contrib-jshint":"^0.11.2","grunt-contrib-uglify":"^0.9.2","grunt-mocha-test":"^0.12.7","mocha":"^2.3.3"},"gitHead":"11a09c94d50a4a0a2e231123baa49e58aa2076ff","homepage":"https://github.com/kloshih/begin","_id":"begin@0.2.1","_shasum":"647d60c9665df3309f46e0043163488929c4380c","_from":".","_npmVersion":"2.5.1","_nodeVersion":"0.12.1","_npmUser":{"name":"kloshih","email":"kloshih@gmail.com"},"dist":{"shasum":"647d60c9665df3309f46e0043163488929c4380c","tarball":"https://registry.npmjs.org/begin/-/begin-0.2.1.tgz","integrity":"sha512-mHbppmWSgSV9Qlii0x/Tlr5NnjOaZxmIQ2COl1tooRVxhrrn0HH5OEiK5LBz60ZSrTHEqc9rVN2ZJddPsFoeww==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCqG3dyr/xirSj6fOEKBCTuai5zn6knmgD2sGJbx9ZhuwIgRI0NZRWJLoTrlDjBDktY/rufokuFhwOQYIgHR7dir94="}]},"maintainers":[{"name":"kloshih","email":"kloshih@gmail.com"}],"_npmOperationalInternal":{"host":"packages-5-east.internal.npmjs.com","tmp":"tmp/begin-0.2.1.tgz_1454971203910_0.25900441920384765"}}},"maintainers":[{"name":"kloshih","email":"kloshih@gmail.com"}],"time":{"modified":"2022-06-13T04:29:52.565Z","created":"2011-02-24T15:47:38.085Z","0.1.0":"2011-02-24T15:47:38.233Z","0.2.1":"2016-02-08T22:40:05.477Z"},"author":{"name":"Lo Shih"},"readme":"\n# begin\n\n**begin** is a small yet powerful asynchronous flow control library for node and browsers.\n\n```js\n\tvar begin = require('begin');\n\t\n\tbegin()\n\t  then(function() { doStep1(this) }).\n\t  each(function() { return [1, 2, 3] })\n\t\tthen(function(i) { doSomethingWithItem(i, this) }).\n\t  end().\n\t  catch(function(err) { console.log(\"Error: \" + err); this(err) })\n\tend();\n  \n```js\n\n    var begin = require('begin');\n    var path = require('path');\n    var StringDecoder = require('string_decoder').StringDecoder;\n\n    function countLinesInDirectory(dir, callback) {\n      var lineCounts = {};\n      var queue = [dir];\n      return begin().\n      \n        // Pop the next directory in the queue\n        while(function() { return this.dir = queue.shift() }).\n        \n          // Read the directory \n          each(function() { fs.readdir(this.dir, this) }).\n          \n            then(function(name) {\n              this.name = name;\n              this.file = path.join(this.dir, this.name);\n              fs.stat(this.file, this);\n            }).\n            \n            case().\n            \n              /* If this is a directory, then queue the directory */\n              when(function() { return this.stat.isDirectory }).\n                then(function() {\n                  queue.push(this.file);\n                  return null;\n                }).\n              \n              /* If this is a file, stream and count the lines */\n              when(function() { return this.stat.isFile }).\n                then(function() {\n                  return countLinesInFile(this.file);\n                }).\n                then(function(lineCount) {\n                  lineCounts[this.filePath] = lineCount;\n                  return null;\n                }).\n                \n            end().            \n            \n            catch(function(err) {\n              if (err.code === 'EACCES')\n                this(null);\n              else\n                this(err);\n            }).\n            \n          end().\n          \n        end().\n        \n      end(callback);\n    }\n    \n    function countLinesInFile(file, callback) {\n      var lineCount = 0;\n      var buffer = '';\n      var decoder = new StringDecoder('utf8');\n      return begin().\n        stream(function() { return fs.createReadStream(file, {encoding:'utf8'}) }).\n          then(function(data) {\n            buffer += decoder.write(data);\n            var parts = buffer.split(/\\r?\\n/);\n            buffer = parts.pop();\n            lineCount += parts.lenght;\n            return null;\n          }).\n        end().\n        then(function() {\n          if (buffer)\n            lineCount++;\n          return lineCount;\n        }).\n      end();\n    }\n    \n    countLinesInDirectory('/tmp')\n      .then(function(lineCounts) {\n        console.log(lineCounts);\n      });\n      \n```\n\t\n### <a id=\"plugin\"></a> Plugins\n\t\n**begin** is extensible via plugins. The [begin.plugin()](#plugin) method allows you to define, redefine or remove begin operations as you see fit. The plugin method takes \n\n\tbegin.plugin(blockMethods, pluginMethods);\n \nWhere ***blockMethods*** is an object containing DSL methods added to [blocks](#block), ***pluginMethods*** is an object containing methods for the plugin including an **init** method, which is called when initializaing\n\n\tbegin.plugin('Wait', {\n\t  init: function(timeout, func) {\n\t  \tthis.timeout = timeout;\n\t  \tthis.func = func;\n\t  },\n\t  run: function(args, context, callback) {\n\t    setTimeout(function() {\n\t      callback.apply(_this, args);\n\t    }, this.timeout);\n\t  },\n\t}, {\n\t  wait: function(timeout, func) {\n\t  \tvar step = new begin.Wait(timeout, func);\n\t  \tthis.steps.push(step);\n\t  \treturn step;\n\t  },\n\t});\n\n\tbegin.plugin(\n\t  {\n\t\tpoll: function(interval, func) {\n\t\t  var step = new Poll(this, interval, func);\n\t\t  return step;\n\t\t},\n\t  },\n\t  {\n\t\tinit: function(interval, func) {\n\t\t  this.interval = interval;\n\t\t  this.func = func;\n\t\t},\n\t\trun: function(args, context, callback) {\n\t\t  var _this = this;\n\t\t  this.invoke(this, this.func, slice.call(args, 1), context, function(err, result) {\n\t\t\tif (err)\n\t\t\t  return callback && callback(err)\n\t\t\tif (result)\n\t\t\t  return callback && callback.apply(_this, args)\n\t\t\tsetTimeout(function() {\n\t\t\t  _this.run(args, context, callback);\n\t\t\t}, _this.interval)\n\t\t  }\n\t\t},\n\t  },\n\t)\n\n\tvar begin = require('begin'),\n\t    fs = require('fs'),\n\t    path = require('path');\n\t\n\tfunction countLinesInFiles(dir, callback) {\n\t  begin().\n\t\t// Throw is equivalent to this(err) and return of any\n\t\t// non-undefined is equivalent to this(null, result).\n\t\tthen(function()\t   { if (!dir) throw new Error(\"dir required\");\n\t\t\t\t\t\t\t\treturn true }).\n\t\t// Each calls the function asynchronously and iterates in parallel\n\t\teach(function()\t   { fs.readdir(task.dir, this) }).\n\t\t  then(function()\t { fs.readFile(this.file, 'utf8', this) }).\n\t\t  then(function(data) { return data.split(/\\r\\n|\\r|\\n/).length }).\n\t\t  // Catches errors like when fs.readFile() is called for a directory\n\t\t  catch(function(err) { return 0 }).\n\t\tend().\n\t\t// Each results in an array of results for each file\n\t\tthen(function(counts) { var sum = 0;\n\t\t\t\t\t\t\t\tcounts.forEach(function(count) { sum += count });\n\t\t\t\t\t\t\t\treturn sum }).\n\t\tfinally(function(err, total) {\n\t\t  total || (total = 0);\n\t\t  console.log(\"Found err=\" + err + \" +  total=\" + total);\n\t\t  this(err, total);\n\t\t}).\n\t  // Return the last value, the sum of line numbers in all files or a\n\t  // fs.readdir() error if one occurs\n\t  end(callback);\n\t}\n\n### Why Yet Another Async Library for Node.js?\n\nThere are already several excellent asynchronous libraries out there. Why would we want another one? The primary motivation to create a new async library was a matter of semantics. Often times, when writing asynchronous functions, you want the flexibility to mix both synchronous and asynchronous operations, nest parallel and serial operations, all using the concise semantics that minimize nested callbacks.\n\nLet's take a look an example function and its possible implementations:\n\n\t/* Counts the number of lines in each file matching the optional *filter* in\n\t * the directory given and returns information to *callback(err, info)*\n\t * where *info* is contains the following keys:\n\t * \n\t * - `lines` - An object mapping file names to number of lines\n\t * - `total` - The total number of lines\n\t * - `files` - The total number of files\n\t * - `average` - The average number of lines per file\n\t * \n\t * The optional *filter* function takes the arguments: `file`, `stat`,\n\t * `callback`, where `file` is the file name, `stat` is a fs.Stat for the\n\t * file and should call `callback(err, matches)` where `matches` is a truthy\n\t * value if the filter includes this file.\n\t * \n\t * This function uses *lookupFromCache(stat, callback)* and \n\t * *saveToCache(stat, count, callback)* to use a cache of line counts to \n\t * reduce file I/O.\n\t * \n\t * @param dir The directory name @param filter The optional filter function\n\t * @param callback The callback function\n\t */\n\tfunction countLinesInDirectory(dir, filter, callback) {\n\t  ...\n\t}\n\nThis is what it looks like implemented with **begin** done in 39 lines of code.\n\n\tvar begin = require('begin'),\n\t\tpath = require('path');\n\t\n\tfunction countLinesInDirectory(dir, filter, callback) {\n\t  var result = { files:0, lines:{}, total:0, average:null, errors:{} };\n\t  begin().\n\t\teach(function() { fs.readdir(dir, this) }).\n\t\t  then(function(name) {\n\t\t\tthis.file = path.join(dir, name);\n\t\t\tfs.stat(this.file, this);\n\t\t  }).\n\t\t  if(function(stat) {\n\t\t\tthis.stat = stat;\n\t\t\tif (!stat.isFile())\n\t\t\t  return false;\n\t\t\telse if (filter)\n\t\t\t  filter(this.file, stat, this)\n\t\t\telse\n\t\t\t  return true;\n\t\t  }).\n\t\t\tthen(function(stat) { lookupFromCache(stat, this) }).\n\t\t\tif(function(count) { return count < 0 }).\n\t\t\t  then(function() { fs.readFile(this.file, this) }).\n\t\t\t  then(function(data) {\n\t\t\t\tthis.count = data.split(/\\r\\n|\\r|\\n/).length;\n\t\t\t\tsaveInCache(this.stat, this.count, this);\n\t\t\t  }).\n\t\t\t  get('count').\n\t\t\tend().\n\t\t\tcatch(function(err) { errors[this.file] = err; return -1 }).\n\t\t\tthen(function(count) {\n\t\t\t  if (count > 0)\n\t\t\t\ttotal += lines[this.file] = count; \n\t\t\t  result.files++;\n\t\t\t  return true;\n\t\t\t}).\n\t\t  end().\n\t\tend().\n\t\tthen(function() {\n\t\t  result.average = result.files > 0 ? result.total / result.files : 0;\n\t\t  return result;\n\t\t}).\n\t  end(callback);\n\t}\n\nIn contrast, here is an implementation of the function using **async** in 68 lines of code.\n\n\tvar async = require('async'),\n\t\tpath = require('path');\n\n\tfunction countLinesInDirectory(dir, filter, callback) {\n\t  if (typeof(dir) !== 'string')\n\t\treturn callback && callback(new TypeError('path must be a string'));\n\t  var result = { files:0, lines:{}, total:0, average:null, errors:{} };\n\t  async.waterfall([\n\t\tfunction(cb) {\n\t\t  fs.readdir(dir, cb);\n\t\t},\n\t\tfunction(files, cb) {\n\t\t  async.forEach(files, function(name, cb) {\n\t\t\tvar file = path.join(dir, name);\n\t\t\tasync.waterfall([\n\t\t\t  function(cb) { fs.stat(file, cb) },\n\t\t\t  function(stat, cb) {\n\t\t\t\tif (!stat.isFile())\n\t\t\t\t  return cb();\n\t\t\t\tasync.waterfall([\n\t\t\t\t  function(cb) {\n\t\t\t\t\tif (filter)\n\t\t\t\t\t  filter(file, stat, cb)\n\t\t\t\t\telse\n\t\t\t\t\t  cb(null, true)\n\t\t\t\t  },\n\t\t\t\t  function(matched, cb) {\n\t\t\t\t\tif (matched) {\n\t\t\t\t\t  async.waterfall([\n\t\t\t\t\t\tfunction(cb) {\n\t\t\t\t\t\t  try {\n\t\t\t\t\t\t\tlookupFromCache(stat, cb)\n\t\t\t\t\t\t  } catch (err) {\n\t\t\t\t\t\t\tcb(err)\n\t\t\t\t\t\t  }\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfunction(count, cb) {\n\t\t\t\t\t\t  result.files++;\n\t\t\t\t\t\t  if (count < 0) {\n\t\t\t\t\t\t\tasync.waterfall([\n\t\t\t\t\t\t\t  function(cb) { fs.readFile(file, 'utf8', cb) },\n\t\t\t\t\t\t\t  function(data, cb) {\n\t\t\t\t\t\t\t\tvar count = data.split(/\\r\\n|\\r|\\n/).length;\n\t\t\t\t\t\t\t\tresult.total += result.lines[file] = count;\n\t\t\t\t\t\t\t\tsaveInCache(stat, count, cb)\n\t\t\t\t\t\t\t  },\n\t\t\t\t\t\t\t], cb);\n\t\t\t\t\t\t  } else {\n\t\t\t\t\t\t\tresult.total += result.lines[file] = count;\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t  }\n\t\t\t\t\t\t}\n\t\t\t\t\t  ], cb)\n\t\t\t\t\t} else {\n\t\t\t\t\t  cb();\n\t\t\t\t\t}\n\t\t\t\t  }\n\t\t\t\t], cb);\n\t\t\t  },\n\t\t\t], cb);\n\t\t  }, cb)\n\t\t},\n\t\tfunction() {\n\t\t  result.average = result.files > 0 ? result.total / result.files : 0;\n\t\t  cb(null, result);\n\t\t},\n\t  ], callback);\n\t}\n\nThis **async** version of `countLinesInDirectory()`, which probably could be improved, calls **async** 6 times, once whenever there is a switch off between iteration and serial operations or when control is handed back to your code to handle conditionals. The **begin** implementation above is calls **begin** just once. This not only makes code more readable but also less error prone. \n\nThe primary issue with using **async**, however, is the same issue when writing asynchronous code without using a library: some asynchronous operations still require nested callbacks. In this example **async** code, callbacks are nested 6-deep (lines 12, 13, 17, 27, 37 and 42). Minimizing nested callbacks is the primary motivation to use an async library. The **begin** implementation above doesn't nest callbacks. \n\n### Features\n\n* Uses DSL semantics to chain statements\n* Supports synchronous and asynchronous statements\n* Supports the following \n  * `begin()`…`end()` blocks of steps\n  * `then()` statements\n  * `if()`…`elseif()`...`else()`...`end()` conditionals \n  * `catch()` and `finally()` error handling\n  * `split()` for parallel steps\n  * `each()`…`end()` parallel and serial iteration over arrays or objects\n  * `while()`…`end()` serial looping\n  * `pipeline()`…`end()` step pipelining\n  * `wait()` and `poll()` for unconditional or conditional timeouts\n  * `on()` for event observation with timeout\n  * `get()` and `set()` for working with context variables\n  * `map()`, `reduce()` and `finalize()` for calculations\n* Supports embedded *blocks* of statements\n* Supports cancelling (or aborting) a begin from within callbacks\n* Supports `if`, `elseif` and `else` asynchronous conditionals\n* Supports asynchronous `each` \n* Supports `catch` and `finally`\n* Contextual data via properties on `this`\n* No external dependencies\n* Lightweight\n* Extensible via plugins\n\n### Supporting Cancellation\n\n    var block = begin().\n      then(function() {\n      \tvar timer = setTimeout(this, 60e3);\n      \tthis.cancel = function() {\n      \t  clearInterval(timer);\n      \t  return true;\n      \t};\n      }).\n      then(function() {\n        var anotherTimer = setTimeout(this, 60e3);\n      }).\n      then(function() {\n      \tconsole.log(\"Done\");\n      \treturn true;\n      }).\n    end();\n    \n    // Then later…\n    block.cancel();\n\nIf you set the `cancel` function on `this`, the function will be used to cancel the current step or steps. If those current steps aren't cancellable, an error is thrown.\n\n\n### Statements\n\n- Creating Blocks\n  - [begin](#begin) <br/>\n\tStarts a new block of statements\n  - [end](#end) <br/>\n\tEnds a block of statements\n- Evaluating Statements\n  - [step](#step) <br/>\n\tOne statement step\n  - [if](#if), [elseif](#if), [else](#if) <br/>\n\tConditionals\n  - [each](#if), [split](#if) <br/>\n\tParallel iteration and operations\n  - [while](#if), [until](#if) <br/>\n\tConditional looping\n- Waiting for Timeouts and Events\n  - [poll](#if), [wait](#if) <br/>\n\tConditional and unconditional timeouts\n  - [on](#if), [once](#if) <br/>\n\tObserving events with timeouts\n- Using Context Variables\n  - [set](#if), [get](#if) <br/>\n\tSetting and getting context variables\n- Handling Errors\n  - [catch](#if) <br/>\n\tCatching and handling errors\n  - [finally](#if) <br/>\n\tCleaning up\n\n\n### How node-begin works\n\n\tbegin().\n\t  then(function() {\n\t\tfs.readFile('./greeting.txt', 'utf8', this);\n\t  }).\n\t  then(function(greeting) {\n\t\tif (greeting.length == 0)\n\t\t  throw new Error(\"No greeting\");\n\t\treturn greeting;\n\t  }).\n\tend(callback);\n\n**begin** allows you to declare a sequence of steps which may be synchronous or asynchronous depending on how you write the functions you provide. These functions take in the arguments from the results of the previous step and return results to the following step.\n\nThere are 4 ways to return results in a function:\n\n1. Call or cause something else to call `this(err)` \n2. Throw an error: `throw err` is equivalent to `this(err)`\n3. Call or cause something else to call `this(null, result1, result2, ...)`\n4. Return a result other than undefined: `return result` is equivalent to `this(null, result)`\n\nThis obviates the need for \n\nWhen an error occurs the result all subsequent steps are skipped other than the next `catch` and/or any `finally` steps. See `catch` and `finally` below.\n\n### Synchronous and asynchronous behavior\n\nA begin is executed immediately when you call `end()` on the top-level block. If\nall of your steps are synchronous, the begin completes synchronously. The begin \nmodule doesn't use `process.nextTick(…)` or `setTimeout(…)` to evaluate. This\nallows you to bring initial synchronous code, such as setting initial state, inside a **begin** which can benefit from error handling and callback chaining. \n\n\tfunction doSomeWork(file, callback) {\n\t  var self = this;\n\t  begin().\n\t\tthen(function() {\n\t\t  if (self.status === 'working')\n\t\t\tthrow new Error('Already working');\n\t\t  self.status = 'working';\n\t\t  fs.readFile(file, this)\n\t\t}).\n\t\tthen(function(data) {\n\t\t  self.processData(data, this)\n\t\t}).\n\t\tfinally(function() {\n\t\t  self.status = 'done';\n\t\t  return true;\n\t\t})\n\t  end(callback);\n\t}\n\nIn this example, we put the `self.status` checking statements inside the first step. Since the **begin** evaluates immediately when you `end()` the top level block, the `self.status` check is evaluated synchronously. This gives you the benefits of detecting if \n\n\t\t  if (self.status === 'working')\n\t\t\tthrow new Error('Already working');\n\ninside the first step. Since it is synchronous, it gets evaluated before `doSomeWork(…)` returns. \n\n#### Cancelling or Timing out Begins\n\nOccasionally, you may want to limit the amount of time a **begin** evaluates. You can create a timeout on a **begin** using the `timeout` option, specifying the milliseconds after which the entire **begin** produces an error.\n\n\tbegin(null, {timeout:1000}).\n\t  then(function() { doIt(this) }).\n\tend(callback);\n\nIn this example, if `doIt(…)` step takes more than one second, the step results in an error, forwarding the error to `callback`.\n\nYou may additionally want to programmatically cancel a **begin** regardless of the steps remaining to be taken. To do this, each step that requires it, define `this.cancel` as a function that works to cancel the step. \n\n\tfunction doSomeWork(callback) {\n\t  var self = this;\n\t  this.work = begin().\n\t\tthen(function() {\n\t\t  doIt(this);\n\t\t  this.cancel = function() { stopIt(this) };\n\t\t}).\n\t\tfinally(function() {\n\t\t  self.work = null;\n\t\t  return true;\n\t\t})\n\t  end();\n\t}\n\tfunction cancel() {\n\t  if (this.work)\n\t\tthis.work.cancel();\n\t}\n\n### Using with underscore.js\n\nIf you already use underscore.js throughout your project, node-begin extends \nunderscore with a `begin()` function so that you can write your begins like this:\n\n\t_.begin().\n\t  then(function() { ... }).\n\tend();\n  \nThis way, you'll  only have to `require('begin')` just once in your project to make it available to all of your modules. \n\n### Context variables\n\nOften times when writing asynchronous functions, you want to pass around state\nbut end up writing a lot of glue just to pass along a variable.\n\n  _.begin().\n\t  then(function() { getFile(this) }).\n\t  then(function(file) {\n\t\tvar callback = this;\n\t\tfs.stat(file, function(err, stat) { callback(err, file, stat) });\n\t  }).\n\t  then(function(file, stat) {\n\t\tif (!stat.exists) \n\t\t  throw new Error(\"File, '\" + file + \"' doesn't exist\");\n\t\treturn file;\n\t  }).\n\tend();\n\nInstead, you can add any property you'd like to `this` which will be available\nto all subsequent functions. The above begin can be instead written as:\n\n\t_.begin().\n\t  then(function() { getFile(this) }).\n\t  then(function(file) {\n\t\tthis.file = file;\n\t\tfs.stat(this.file, this);\n\t  }).\n\t  then(function(stat) {\n\t\tif (!stat.exists) \n\t\t  throw new Error(\"File, '\" + this.file + \"' doesn't exist\");\n\t\treturn this.file;\n\t  }).\n\tend();\n  \nThere are also `set` and `get` steps that allow you to work with context \nvariables. \n\n\t_.begin().\n\t  then(function() { getFile(this) }).\n\t  set('file').\n\t  then(function(file) {\n\t\tfs.stat(this.file, this);\n\t  }).\n\t  then(function(stat) {\n\t\tif (!stat.exists) \n\t\t  throw new Error(\"File, '\" + this.file + \"' doesn't exist\");\n\t\treturn this.file;\n\t  }).\n\tend();\n\nAll steps have access to the contextual variables from prior steps. Steps, such\nas `each()` and `split()` that kick off parallel execution get their own \nshallow copy of contextual variables so that they don't clobber each other. \nTHis a\n\n\n\n\t\n\tbegin().\n\t  // Read in list of files from file-list.txt\n\t  then(function() { fs.readFile('./file-list.txt', 'utf8', this) }).\n\t  // Each line is the name of a directory\n\t  each(function(data) { return data.split(/\\r\\n|\\n/) }).\n\t\t// List the directory\n\t\teach(function(dir, i) { fs.readdir(dir, this) }).\n\t\t  then(function(file) { if ( }).\n\t\tend().\n\t\tthen(function() {\n\t\t  for (var i = 0, ic = arguments.length; i < ic; i++)\n\t\t\t\n\t\t}).\n\t  \n\t  then(function(data) {  }).\n\t  each(function(data) { return data.split(/\\r\\n|\\n/) }).\n\t\tthen(function(line, i) { fs.readFile(line, this) }).\n\t\t\n\t  end().\n\t  then(function() { ... }).\n\t  catch(function() { ... }).\n\tend(callback);\n\n### <a id=\"each\"></a> each( [*options*,] *func_or_array* )\n\n\teach(function(args, ..) { .. }).\n\t  /* block taking arguments (item, index) */\n\tend()\n\t\n\teach(array).\n\t  /* block taking arguments (item, index) */\n\tend()\n\nIf `func_or_array` is an array, the block is iterated in parallel for each item in the array.\n\nIf `func_or_array` is a function, the result of the function is taken as such an array. This function follows rules of all step functions:\n\n- Takes as arguments the result of the previous step\n- `this` is a callback function\n- May be synchronous or asynchronous\n  - Should call `this(null, array)` or `return array` with the *array* to iterate\n  - Should call `this(err)` or `throw` upon error\n- May use or set context variables on `this`\n\nIf the *array* is falsy, behavior of `each()` is the same as if *array* were an empty array.\n\nA call to `each()` should be followed by DSL-declared block and balanced with an `end()`. The contained block will be executed once in parallel for each item in the *array*. Since `each()`'s block operates in parallel, each iteration of the block gets its own shallow copy of context variables. If statements in the block sets context variables, they are scoped only to the block. \n\nThe result of `each()` is an array of results. If the block results in multiple return values, they are grouped as an array. For example:\n\t\n\teach([1, 2, 3]).\n\t  then(function(x) { this(null, x*2) }).\n\tend().\n\tthen(function(result) { console.log(JSON.stringify(result)) })\n\t// => [2,4,6]\n\n\teach([1, 2, 3]).\n\t  then(function(x) { this(null, x*2, x*2 + 1) }).\n\tend().\n\tthen(function(result) { console.log(JSON.stringify(result)) })\n\t// => [[2,3],[4,5],[6,7]]\n\n\teach([1, 2, 3]).\n\t  then(function(x) { if ((x % 2) == 0) return x; else this(null, x, x*x); }).\n\tend().\n\tthen(function(result) { console.log(JSON.stringify(result)) })\n\t// => [[1,1],2,[3,9]]\n\n### <a id=\"step\"></a> then(*func*)\n\n\tthen(function(..) { .. })\n\nStep statements are executed sequentially. This function follows rules of all step functions:\n\n- Takes as arguments the result of the previous step\n- `this` is a callback function\n- May be synchronous or asynchronous\n  - Should call `this(null, result, …)` or `return result` with the result\n  - Should call `this(err)` or `throw` upon error\n- May use or set context variables on `this`\n\n### <a id=\"block\"></a> begin()…end()\n\n\tbegin().\n\t  /* block statements */\n\tend()\n\nBlocks group a set of statements and executes them sequentially, passing the results of one statement as the arguments to the next. Whenever an error occurs, either as a result of a call to `this(err)` or a `throw`, subsequent normal statements are skipped and the first [catch()](#catch) statement is evaluated, which may throw an error itself, in which case, the next [catch()](#catch) statement is evaluated. \n\n##### Working with catch() and finally()\n\n[finally()](#finally) statements are always evaluated in order, regardless of whether an error has occurred or not. For example, \n\n\tbegin().\n\t  then(function()\t   { console.log('step A'); return true }).\n\t  finally(function()\t{ console.log('finally 1'); return true }).\n\t  then(function()\t   { throw Error() }).\n\t  then(function()\t   { console.log('step B'); return true }).\n\t  finally(function()\t{ console.log('finally 2'); return true }).\n\t  catch(function(error) { console.log('catch/throw C'); this(error) })\n\t  finally(function()\t{ console.log('finally 3'); return true }).\n\t  catch(function(error) { console.log('catch D'); this() })\n\t  finally(function()\t{ console.log('finally 4'); return true }).\n\tend()\n\t/* \n\t * Outputs:\n\t *   step A\n\t *   finally 1\n\t *   finally 2\n\t *   catch/throw C\n\t *   finally 3\n\t *   catch D\n\t *   finally 4\n\t */\n\n##### Giving end() a callback\n\n\tbegin().\n\t  /* block statements */\n\tend(callback)\n\nIf you provide [end()](#block) with a *callback* function, it is executed as if the *callback* were provided to a [finally()](#finally) appended to the end of the block. This is provided as a convenience for the common use case of passing along errors and results. \n\n\t function doSomeWork(callback) {\n\t   begin()\n\t\t /* block statements */\n\t   end(callback);\n\t }\n\n\n### <a id=\"stream\"></a> stream(*func*)…end()\n\n\tstream({}, function() { return stream; }).\n\t  then(function() { … }).\n\t  then(function() { … }).\n\tend()\n\nStreams iterate over data items in an event stream. By default, streams observe the events 'data', 'error' and 'close'.   \n\n### Cancelling\n\n\tthen(function() {\n\t  var timer = setTimeout(this, 60e3, null, \"test\");\n\t  this.onCancel(function() {\n\t    clearTimeout(timer);\n\t    return null;\n\t  });\n\t})\n\nThe cancel function provides a mechanism to cancel the current step. A block may be cancelled at any time.\n\n\n### <a id=\"pipeline\"></a> pipeline(*func*)…end()\n\n\tpipeline(function() { return array }).\n\t  then(function() { … }).\n\t  then(function() { … }).\n\t  then(function() { … }).\n\t  then(function() { … }).\n\tend()\n\nPipelined block works just like [each()](#each), evaluating a block over each entry in an array or object, except  \n","readmeFilename":"README.md","description":"Asynchronous flow control for node.js and browsers","homepage":"https://github.com/kloshih/begin","keywords":["flow","control","async","asynchronous"],"repository":{"type":"git","url":"https://github.com/kloshih/begin.git"},"bugs":{"url":"https://github.com/kloshih/begin/issues"},"license":"BSD"}