{
  "name": "ocsteps",
  "version": "0.2.21",
  "description": "ocSteps 是一个JavaScript异步执行辅助工具，主要用于支持 Node.js 中的大量异步API以及操作，以及前端浏览器里的异步任务（例如Ajax）。",
  "main": "PackageManager.js",
  "scripts": {
    "test": "make"
  },
  "repository": {
    "type": "git",
    "url": "git@github.com:OpenComb/ocSteps.git"
  },
  "author": {
    "name": "alee chou"
  },
  "license": "MIT",
  "devDependencies": {
    "should": "*",
    "mocha": "*"
  },
  "readme": "[![Build Status](https://travis-ci.org/OpenComb/ocSteps.png)](https://travis-ci.org/OpenComb/ocSteps)\n\n# ocSteps\n\n__ocSteps__ 是一个JavaScript异步执行辅助工具，主要用于支持 Node.js 中的大量异步API以及操作，以及前端浏览器里的异步任务（例如Ajax）。如果你听说过“回调地狱”这个词，那么，__ocSteps__ 的用途就很好解释了：它尝试定义“回调天堂”。\n\n__ocSteps__ 维护一个动态的任务链，任务链上的每个节点都是一个可执行函数，这些函数称为 step ，ocSteps 会依次执行任务链上的每个 step 。任务链是动态的，可以在执行过程中向任务链添加 step ，这是 ocSteps 和其他流行的异步操作库的主要区别（例如 [Step](https://github.com/creationix/step), [Async.js](https://github.com/caolan/async)）：不是提供各种规则来定义执行顺序，而是在任务链的执行过程中逐步定义任务链。\n\n> 根据我最近的Node.js开发经验，静态地定义任务链结构，实际上会制造许多繁琐的编码工作；而动态地“演进”任务链，更吻合我们在思考业务逻辑时的思路，能让开发编码更加流畅，并且明显减少编码工作。\n\n__ocSteps__ 参考了 [Step](https://github.com/creationix/step) 的设计，但是规则还要更简单（ocSteps包括注释和疏散的空行在内也只有200+行代码）；并且 ocSteps 是为复杂、动态的任务链而设计。\n\n\n* [快速开始] (#-3)\n* [异步操作] (#-4)\n\t* [暂停计数器] (#-5)\n\t* [并发任务] (#-6)\n\t* [recv 和 prevReturn] (#recv--prevreturn)\n* [动态任务链] (#-7)\n* [终止任务链] (#-8)\n* [异常处理] (#-9)\n* [事件] (#-10)\n\t* [done] (#done)\n\t* [uncatch] (#uncatch)\n* [绑定参数] (#-11)\n* [绑定对象] (#-12)\n* [分支] (#-13)\n* [循环] (#-14)\n* [在浏览器中使用] (#-15)\n\n\n\n\n## 安装\n\n```\n$ npm i ocsteps\n```\n\n## 测试\n\n```\n$ npm i -d\n$ make test\n```\n\n## 升级日志\n\n[History.md] (History.md)\n\n\n## 快速开始\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\n// 和 Step 的用法很像\nSteps(\n\n\t// 前一个函数的 return， 作为下一个函数的参数\n\tfunction(){\n\t\tvar i = 1 ;\n\t\tconsole.log('step ',i) ;\n\t\treturn ++i ;\n\t}\n\n\t, function(i){\n\t\tconsole.log('step ',i) ;\t\t\n\t\treturn ++i ;\n\t}\n\n\t, function(i){\n\t\tconsole.log('step ',i) ;\n\t\treturn ++i ;\n\t}\n\n) () ; // 连续调用，开始执行任务链\n```\n\n输出的结果是：\n\n```\nstep 1\nstep 2\nstep 3\n```\n\n也可以将任务链的定义和执行分开，先定义好，晚一点再执行它\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nvar steps = Steps(\n\n\tfunction(){\n\t\tvar i = 1 ;\n\t\tconsole.log('step ',i) ;\n\t\treturn ++i ;\n\t}\n\n\t, function(i){\n\t\tconsole.log('step ',i) ;\t\t\n\t\treturn ++i ;\n\t}\n) ;\n\n\nsteps.step(function(i){\n\tconsole.log('step ',i) ;\n\treturn ++i ;\n}) ;\n\n\n// 执行任务链\nsteps() ;\n\n```\n\n## 异步操作\n\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\tfunction ()\n\t{\n\t\tfs.readFile(\"/some/file/path\",this.hold()) ;\n\t}\n\t\n\t, function (err,buff)\n\t{\n\t\tif(err)\n\t\t{\n\t\t\tthrow new Error(err) ;\n\t\t}\n\t\t\n\t\tconsole.log(buff.toString()) ;\n\t}\n) () ;\n```\n\n调用 `hold()` 会让任务链的执行暂停，并且返回一个 release函数，直到这个release函数被调用后，任务链才继续执行。release接受到的参数，会传递给下一个 step function 。\n\n通常将`hold()`返回的release函数 作为某个异步操作的回调函数。\n\n\n在访问 mongodb 时使用 hold/release\n```javascript\nvar mongodb = require('mongodb');\n\nvar steps = Steps(\n\n\tfunction()\n\t{\n\t\t// 连接到 mongodb 服务器\n\t\tvar server = new mongodb.Server('127.0.0.1',27017) ;\n\t\tnew mongodb.Db(\"your-db-name\",server,{w:1})).open(this.hold()) ;\n\n\t\tthis.step(function(err,client)\n\t\t{\n\t\t\tif(err) throw err ;\n\t\t\treturn new mongodb.Collection(client,\"your-collection-name\") ;\n\t\t}) ;\n\t}\n\n\t, function(collection)\n\t{\n\t\tvar release = this.hold() ;\n\t\tvar count = 0 ;\n\n\t\tcollection.find().each(function(err,doc){\n\t\t\tif(err)\n\t\t\t{\n\t\t\t\tsteps.throw(err) ;\n\t\t\t\treturn ;\n\t\t\t}\n\n\t\t\tif(doc)\n\t\t\t{\n\t\t\t\tconsole.log(doc) ;\n\t\t\t\tcount ++ ;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\trelease(count) ;\n\t\t\t}\n\t\t})\n\t}\n\n\t, function(count)\n\t{\n\t\tconsole.log(\"total:\"+count) ;\n\t}\n\n) () ;\n\n```\n\n\n\n\n### 暂停计数器\n\n> 可以连续调用多次 `hold()` ，每调用一次 `hold()` 任务链的暂停计数器 +1，并返回一个 release 函数，暂停计数器>0 时任务链暂停；\n> 每个 release 函数被回调时，暂停计数器 -1，当 暂停计数器<1 时，任务链恢复执行。\n\n\n### 并发任务\n\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction stepA(){\n\t\tconsole.log( new Date() ) ;\n\t\tsetTimeout(this.hold(),1000) ;\n\t\tsetTimeout(this.hold(),2000) ;\n\t\tsetTimeout(this.hold(),3000) ;\n\t}\n\n\t, function stepB(){\n\t\tconsole.log( new Date() ) ;\n\t}\n\n) () ;\n```\n\n两次输出的时间会相差 3秒，因为最长一次 setTimeout() 是3秒 。\n\n上面这个例子的执行过程如下：\n\n```\nstepA() -> hold() 1 pause! -> 1000ms -> release() 2\n           hold() 2        -> 2000ms -> release() 1\n           hold() 3        -> 3000ms -> release() 0 resume! -> stepB()\n```\n\n\n### recv 和 prevReturn\n\n所有 hold() 在 release 时 接收到的参数，都会保存在 recv 属性中。它是一个二维数组，第一维下标表示对应第几次 hold() ，第二维下标表示第几个参数。\n\n用数字下标到 recv 里取数据，不是一个很好的方式，这给程序加入了“神秘数字”的“坏味道”，更好的方法是：\n\n```\nhold(argName1,argName2,argName3 ...) ;\n```\n\n这是一个文件操作的例子\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\nvar fs = require(\"fs\") ;\n\n\nSteps(\n\n\t// 检查文件是否存在\n\tfunction(){\n\t\tfs.exists(\"/some/folder/a.txt\",this.hold('existsA')) ;\n\t\tfs.exists(\"/some/folder/b.txt\",this.hold('existsB')) ;\n\t\tfs.exists(\"/some/folder/c.txt\",this.hold()) ;\n\t}\n\n\t// 读取文件\n\t, function(existsC){\n\t\n\t\tthis.recv.existsA\n\t\t\t&& fs.readFile(\"/some/folder/a.txt\",this.hold('errA','buffA')) ;\n\t\t\n\t\tthis.recv.existsA\n\t\t\t&& fs.readFile(\"/some/folder/a.txt\",this.hold('errA','buffA')) ;\n\t\t\n\t\texistsC\n\t\t\t&& fs.readFile(\"/some/folder/c.txt\",this.hold()) ;\n\t}\n\n\t// 输出文件\n\t, function(buffC){\n\t\n\t\t// 读文件遇到错误，抛出异常\n\t\tif(this.recv.errA||this.recv.errB||this.recv.errC)\n\t\t{\n\t\t\tthrow new Error( this.recv.errA||this.recv.errB||this.recv.errC ) ;\n\t\t}\n\t\n\t\tthis.recv.buffA\n\t\t\t&& console.log( this.recv.buffA.toString() ) ;\n\t\t\t\n\t\tthis.recv.buffB\n\t\t\t&& console.log( this.recv.buffB.toString() ) ;\n\t\t\t\n\t\tbuffC\n\t\t\t&& console.log( buffC.toString() ) ;\n\t}\n\t\n) () ;\n```\n\n\n\n如果不需要中间的某个参数，可以用 `null` 占位：\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nfunction someAsyncFunction(callback){\n\tsetTimeout(function(){\n\t\tcallback(1,2,3) ;\n\t},0) ;\n}\n\t    \nSteps(\n    function stepA(){\n    \tsomeAsyncFunction( this.hold('a',null,'b') ) ;\n    \t\n    \treturn \"hello!\" ;\n    }\n    \n    , function stepB(){\n    \tconsole.log(this.recv.a) ;\n    \tconsole.log(this.recv.b) ;\n    \tconsole.log(this.prevReturn) ;\n    }\n\n) () ;\n```\n\n输出：\n```\n1\n3\nhello!\n```\n\n\n`prevReturn` 和 `recv`作用类似，它提供的是前一个 step function 的返回值。\n\n\n\n\n\n\n## 动态任务链\n\n`step()` 和 `appendStep()` 方法分别用于向任务链的当前位置和末尾动态地添加 step function。\n\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction funcA(){\n\n\t\tconsole.log(\"funcA\") ;\n\n\t\t// 插入 step函数\n\t\tthis.step(function funcB(){\n\t\t\tconsole.log(\"funcB\") ;\n\t\t}) ;\n\n\t\t// 将 step函数 添加到任务链的末尾\n\t\tthis.appendStep(function funcC(){\n\t\t\tconsole.log(\"funcC\") ;\n\t\t}) ;\n\t}\n\n\t, function funcD(exists){\n\t\tconsole.log(\"funcD\") ;\n\t}\n\n) () ;\n```\n\n输出出来的是（d在c的前面）：\n```\nfuncA\nfuncB\nfuncD\nfuncC\n```\n\n任务链最开始的状态是：\n\n```\nfuncA -> funcD\n```\n\n然后在执行 funcA 的时候，`this.step(funcB)`在当前位置插入了 funcB ：\n\n```\n[funcA] -> funcB -> funcD\n```\n(方括号是正在执行的step function)\n\n\n接着，`this.appendStep(funcC)`又在任务链的末尾插入了 funcC，结果就成了这样 ：\n\n```\n[funcA] -> funcB -> funcD -> funcC\n```\n\n\n`this.step()` 和 `this.appendStep()` 都支持多个参数，一次性向任务链添加多个step函数。\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction(){\n\n\t\tconsole.log(\"insert 3 step functions one time: \") ;\n\n\t\t// 一次向任务链插入多个step函数\n\t\tthis.step(\n\t\t\tfunction(){\n\t\t\t\tconsole.log(\"a\") ;\n\t\t\t}\n\t\t\t, function(){\n\t\t\t\tconsole.log(\"b\") ;\n\t\t\t}\n\t\t\t, function(){\n\t\t\t\tconsole.log(\"c\") ;\n\t\t\t}\n\t\t) ;\n\t}\n\n\t, function(){\n\n\t\tconsole.log(\"insert 3 step functions one by one: \") ;\n\n\t\t// 陆续向任务链插入函数\n\t\tthis.step(function(){\n\t\t\tconsole.log(\"1\") ;\n\t\t}) ;\n\t\tthis.step(function(){\n\t\t\tconsole.log(\"2\") ;\n\t\t}) ;\n\t\tthis.step(function(){\n\t\t\tconsole.log(\"3\") ;\n\t\t}) ;\n\t}\n\n) () ;\n```\n\n输出的结果是：\n\n```\ninsert 3 step functions one time:\na\nb\nc\ninsert step function one by one:\n1\n2\n3\n```\n\n一次向`this.step()`传入多个函数，和单独传入，顺序上没有区别。\n\n\n\n## 终止任务链\n\n`terminate()` 能够立即终止整个任务链的执行，包括当前正在执行的 step function。\n\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction(){\n\t\treturn new Error(\"some error occured\") ;\n\t}\n\n\t,  function(err){\n\t\terr && this.terminate() ;   // 遇错终止\n\t\tconsole.log(\"You dont see this text forever.\") ;\t// 此行不会执行\n\t}\n\t\n\t// 后面的step都不会执行\n\t, function()\n\t{\n\t\tconsole.log(\"You dont see this text too.\") ;\n\t}\n\n) () ;\n```\n\n> 通过 `this.terminate()` 终止的任务链，仍然会触发`done`事件。\n\n\n\n## 异常处理\n\n\n可以用 `try()` 和 `catch(body[,finalBody])` 在任务链上标记一个区段，插入到这两者之间的 step 如果抛出异常，会跳过区段内的所有后续 step ，然后由 body 处理该异常(body是一个function)。而无论改区段内是否抛出了异常，最后 finalBody 都会被执行(finalBody也是一个function，可以省略的)。\n\n举个栗子：\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nvar steps = Steps() ;\n\nsteps.try()\n\n\t.step(function(){\n\t\tconsole.log('step 1') ;\n\t})\n\t.step(function(){\n\t\n\t\tsetTimeout(this.hold(function(){\t\n\t\t\tthrow new Error(\"oops\") ;\n\t\t}),100)\n\t\n\t\tconsole.log('step 2') ;\n\t})\n\t.step(function(){\n\t\tconsole.log('step 3') ;\n\t})\n\n\nsteps.catch(\n\n\t// catch body\n\tfunction(error){\n\t\tconsole.log(error.message) ;\t\n\t\tconsole.log(\"and then,there is no THEN ...\") ;  // 然后，就没有然后了。\n\t}\n\t\n\t// final body\n\t,  function(){\n\t\tconsole.log(\"final\") ;\t\n\t}\n) ;\n\n\n// 定义完毕，开始执行任务链\nsteps() ;\n```\n\n输出:\n```\nstep 1\nstep 2\noops\nfinal\nand then,there is no THEN ...\n```\n\n关于异常处理，有以下要点：\n\n* 它们跟经典的 try/catch/final 差不多一个意思。\n\n* `try(step1,step2,...)` 也可以像 `step()` 一样插入 step function ，这样可以让代码再简洁一点\n\n* try-catch 可以嵌套，异常会被所在区段的 catch body 抓到。\n\n* 只有插入到 `try()` 和 `catch()` 之间的step function所抛出的异常，才会被 catch，所以由 `appendStep()` 插入的 step function 的异常可能抓不到，因外它是插到任务链的末尾，而不是当前位置。\n\n* `try()` 和 `catch()` 不必成对出现，只有 `catch()` 是必须的，`try()` 可以省略。\n\n* 没有被抓到的异常，最后会触发 'uncatch' 事件\n\n* `catch(body,finalBody)` 的第一个参数 body,只有在抓到异常时执行，finalBody无论如何都会执行\n\n* `catch()` 如果抓到的异常对象不是预期的，可以在 body function 继续抛出，由更外层处理该异常对象。\n\n\n## 事件\n\n### 事件：done\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction(){\n\t\tconsole.log(\"step 1\") ;\n\t}\n\n\t,  function(){\n\t\tconsole.log(\"step 2\") ;\n\t}\n\n\t,  function(){\n\n\t\t// 终止任务链\n\t\tthis.terminate() ;\n\n\t\tconsole.log(\"step 3\") ;\n\t}\n\n).on(\"done\",function(err){\n\tconsole.log(\"over.\") ;\n}) () ;\n```\n\n输出：\n\n```\nstep 1\nstep 2\nover .\n```\n\n* `this.terminate()` 终止任务链后，仍然会触发\"done\"事件\n\n* `done` 事件触发时会将 uncatch exception 传递给事件函数，否则传入 null\n\n* 可以在 `done` 的事件函数里使用 `prevReturn` 和 `recv` 访问最后一个 step function 的执行结果。\n\n\n### 事件：uncatch\n\n任务链上抛出异常没有被任何 catch(body) 截获，最后就会触发 uncatch 事件。 uncatch 事件不会取消 done 事件\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction(){\n\t\tconsole.log(\"step 1\") ;\n\t}\n\n\t,  function(){\n\t\tconsole.log(\"step 2\") ;\n\t}\n\n\t,  function(){\n\n\t\t// 终止任务链\n\t\tthis.terminate() ;\n\n\t\tconsole.log(\"step 3\") ;\n\t}\n\n).on(\"done\",function(){\n\tconsole.log(\"over.\") ;\n}) () ;\n```\n\n## 绑定参数\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction(){\n\t\treturn \"foo\" ;\n\t} ,\n\n\t[\"bar\"], function(arg){\n\t\tconsole.log( this.prevStep.return ) ;\n\t\tconsole.log( arg ) ;\n\t}\n\n) () ;\n```\n\n输出：\n```\nfoo\nbar\n```\n\n这个程序会输出预先传入的参数 `bar` 而不是从前一个 step函数传来的 `foo` 。\n\n`step()` 除了接收 function 类型参数，还可以接收 Array 类型。Array参数会和后一个 function 绑定，作为 function 执行时的参数列表。\t\n\n这个机制主要应用于循环当中：\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\t// 有问题的方式\n\tfunction(){\n\n\t\tconsole.log(\"Always prints the last time value of the variable i in the for loop: \") ;\n\n\t\tfor(var i=1;i<=3;i++)\n\t\t{\n\t\t\tthis.step(function(){\n\t\t\t\tconsole.log(i) ;\n\t\t\t})\n\t\t}\n\t}\n\n\t// 常用的方式\n\t, function(){\n\n\t\tconsole.log(\"Another way: \") ;\n\n        for(var i=1;i<=3;i++)\n        {\n            (function(arg){\n\n\t            this.step( function(){\n\t\t            console.log(arg) ;\n\t\t        } ) ;\n\n\t        }) (i) ;\n        }\n    }\n\n    // 更好的方式\n\t, function(){\n\n\t\tconsole.log(\"Better way: the value of variable i in each loop has saved, and then pass to step functions: \") ;\n\n        for(var i=1;i<=3;i++)\n        {\n            this.step([i], function(arg){\n                console.log(arg) ;\n            }) ;\n        }\n    }\n\n) () ;\n```\n\n输出的结果是：\n```\nAlways prints the last time value of the variable i in the for loop:\n3\n3\n3\ncorrect way:\n1\n2\n3\nBetter way: the value of variable i in each loop has saved, and then pass to step functions:\n1\n2\n3\n```\n\n如果在循环中使用 `this.step()` ，并在 step function 里访问闭包变量，可能完全不是你想要的结果。\n\n例子里的三种方式，第一种方式是有问题的：执行 step function 输出闭包变量i时，循环已经结束了，所以i总是等于最后一次循环过程中的值：3；\n\n第二种方式可以避免这个问题，这是闭包编程中避免此类问题的常见模式；而第三种方式更简单。\n\n\n\n\n## 绑定对象\n\n可以用 `bind()` 将任务链绑定到一个对象上（这样就可以少用一个闭包变量了……），然后在 step function 内，this 能够继承该对象的所有属性和方法。\n\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\nvar object = {\n\n\tfoo: 'bar'\n\t\n\t, toString: function(){\n\t\treturn this.foo ;\n\t}\n\n}\n\nSteps(\n\n\tfunction(){\n\t\tconsole.log(this.foo) ;\n\t\tconsole.log(this) ;\n\t}\n\t\n\n).bind(object) () ;\n```\n\n> 由于 ie 不支持 __proto__，`bind()` 在全系列 ie 下无效（但不会报错）。\n\n\n`bind()`是一个为框架作者提供的方法，他们可以将 ocSteps 整合到他们的框架中。例如将任务链绑定给控制器，就得到了一个支持异步操作的控制器，那些 step function 实际上就成了控制器的方法。\n\n\n\n## 循环\n\n```javascript\n\nvar Steps = require(\"ocsteps\") ;\n\nSteps(\n\n\tfunction ()\n\t{\n\t\tthis.loop(function(i){\n\t\t\n\t\t\tif(i>3)\n\t\t\t{\n\t\t\t\t// 结束循环\n\t\t\t\tthis.break(i) ;\n\t\t\t}\n\t\t\t\n\t\t\tconsole.log('loop ',i) ;\n\t\t\t\n\t\t\treturn ++i ;\n\t\t}) ;\n\t\t\n\t\t// 传个 loop step 的参数\n\t\treturn 0 ;\n\t}\n\t\n\t// break() 会将收到的参数传递给循环结束后的下一个step\n\t, function(i)\n\t{\n\t\tconsole.log('break ',i) ;\n\t}\n\n) () ;\n\n\n```\n\n输出：\n\n```\nloop 0\nloop 1\nloop 2\nloop 3\nbreak 4\n```\n\n在循环中同样可以调用 `hold()` 和 `step()` 等方法\n\n```javascript\n\nvar Steps = require(\"ocsteps\") ;\n\n\nSteps(\n\n\tfunction ()\n\t{\n\t\tthis.loop(function(i){\n\t\t\n\t\t\tif(i>3)\n\t\t\t{\n\t\t\t\t// 结束循环\n\t\t\t\tthis.break(i) ;\n\t\t\t}\n\t\t\t\n\t\t\tconsole.log('loop ',i) ;\n\t\t\t\n\t\t\t// 异步操作\n\t\t\tvar release = this.hold() ;\n\t\t\tsetTimeout(function(){\n\t\t\t\t// 1秒钟后，将 i 传递给 step \n\t\t\t\trelease(i) ;\n\t\t\t},1000) ;\n\t\t\t\n\t\t\tthis.step(function(i){\n\t\t\t\n\t\t\t\tconsole.log('step in loop ',i) ;\n\t\t\t\t\n\t\t\t\t// 传递给下一次 loop\n\t\t\t\treturn ++i ;\n\t\t\t}) ;\n\t\t}) ;\n\t\t\n\t\t// 传个 loop step 的参数\n\t\treturn 0 ;\n\t}\n\t\n\t// break() 会将收到的参数传递给循环结束后的下一个step\n\t, function(i)\n\t{\n\t\tconsole.log('break ',i) ;\n\t}\n\n) () ;\n\n\n```\n\n\n```\nloop 0\nstep in loop 0\nloop 1\nstep in loop 1\nloop 2\nstep in loop 2\nloop 3\nstep in loop 3\nbreak 4\n```\n\n\n## 分支\n\n\n```javascript\nvar Steps = require(\"ocsteps\") ;\n\n\nSteps(\n\n\tfunction(){\n\t\tconsole.log(\"master step 1\") ;\n\t\treturn 'a' ;\n\t}\n\n\t, function(arg){\n\n\t\tconsole.log(\"master step 2, \",\"input:\",arg) ;\n\n\t\t// 创建一个分支\n\t\tthis.fork(\n\t\t\tfunction(arg){\n\t\t\t\tconsole.log(\"branch step 1, \",\"input: \",arg) ;\n\t\t\t\treturn 'c' ;\n\t\t\t}\n\n\t\t\t, function(arg){\n\t\t\t\tconsole.log(\"branch step 2, \",\"input: \",arg) ;\n\t\t\t\treturn 'd' ;\n\t\t\t}\n\t\t) ;\n\n\t\treturn 'b'\n\t}\n\n\t, function(arg){\n\t\tconsole.log(\"master step 3, \",\"input: \",arg) ;\n\t}\n) () ;\n```\n\n输出：\n```\nmaster step 1\nmaster step 2, input: a\nbranch step 1, input: b\nbranch step 2, input: c\nmaster step 3, input: d\n```\n\n* 分支和主干会自动衔接上的\n\n* 执行分支时，主干暂停，分支执行完毕后，接着执行主干\n\n* 主干能够 catch 分支抛出的异常\n\n* 分支和主干之间，事件是独立的\n\n* 对分支调用 terminate() 不会影响主干\n\n* 分支和主干可以绑定不同的对象\n\n* `fork()` 和 绑定对象，可以使 ocSteps 更好地集成到框架里\n\n\n\n\n## 在浏览器中使用\n\n```html\n\n<script src=\"/some/folder/ocsteps/PackagesManager.js\" ></script>\n<script>\n\nStep(\n\n\tfunction(){\n\t\t$.ajax({\n\t\t\ttype: \"POST\",\n\t\t\turl: \"some.php\",\n\t\t\tdata: \"name=John&location=Boston\",\n\t\t\tsuccess: this.hold(\"msg\")\n\t\t});\n\t}\n\t\n\t, function(){\n\t\n\t\tconsole.log(this.recv.msg) ;\n\t\n\t\t$.ajax({\n\t\t\ttype: \"POST\",\n\t\t\turl: \"some.php\",\n\t\t\tdata: \"name=John&location=Boston\" ,\n\t\t\tsuccess: this.hold(\"data\")\n\t\t});\n\t}\n\t\n\t, function(){\n\t\tconsole.log(this.recv.data) ;\n\t}\n\n) () ;\n\n</script>\n\n\n```\n\n\n---\n\n### Have fun !\n\n\n\n## License\n\n(The MIT License)\n\nCopyright (c) 2013 Alee Chou &lt;aleechou@gmail.com&gt;\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
  "readmeFilename": "README.md",
  "bugs": {
    "url": "https://github.com/OpenComb/ocSteps/issues"
  },
  "_id": "ocsteps@0.2.9",
  "dist": {
    "shasum": "614c1103c09e03fd74b9749e57a665bc35b7683a"
  },
  "_from": "ocsteps@0.2.9",
  "_resolved": "https://registry.npmjs.org/ocsteps/-/ocsteps-0.2.9.tgz"
}
