Comparing version 0.1.10 to 0.2.0
121
chain.js
@@ -1,12 +0,5 @@ | ||
/* | ||
* chainjs | ||
* http://github.com/switer/chainjs | ||
* | ||
* Copyright (c) 2013 "switer" guankaishe | ||
* Licensed under the MIT license. | ||
* https://github.com/switer/chainjs/blob/master/LICENSE | ||
*/ | ||
'use strict'; | ||
'use strict' | ||
var utils = require('./lib/utils.js') | ||
/******************************* | ||
@@ -132,17 +125,17 @@ Chain | ||
if (node.items) { | ||
var proto = that.constructor.prototype | ||
for (var index = 0; index < node.items.length; index++) { | ||
var item = node.items[index] | ||
var xArgs = args | ||
var chainDummy = { | ||
__id: node.id, | ||
__index: index, | ||
__callee: item, | ||
__arguments: xArgs, | ||
var ChainDummy = utils.create(function () { | ||
this.__id = node.id | ||
this.__index = index | ||
this.__callee = item | ||
this.__arguments = xArgs | ||
this.state = that.state | ||
this.props = that.props | ||
}, proto) | ||
var chainDummy = new ChainDummy() | ||
chainDummy.next = utils.bind(proto.next, chainDummy) | ||
state: that.state, | ||
props: that.props | ||
} | ||
chainDummy.__proto__ = that.__proto__ | ||
chainDummy.next = utils.bind(chainDummy.__proto__.next, chainDummy) | ||
xArgs.unshift(chainDummy) | ||
@@ -298,82 +291,2 @@ item.apply(that.props._context, xArgs) | ||
/** | ||
* Util functions | ||
**/ | ||
var utils = { | ||
/** | ||
* forEach | ||
* I don't want to import underscore, it looks like so heavy if using in chain | ||
*/ | ||
each: function(obj, iterator, context) { | ||
if (!obj) return | ||
else if (obj.forEach) obj.forEach(iterator) | ||
else if (obj.length == +obj.length) { | ||
for (var i = 0; i < obj.length; i++) iterator.call(context, obj[i], i) | ||
} else { | ||
for (var key in obj) iterator.call(context, obj[key], key) | ||
} | ||
}, | ||
some: function (arr, iterator) { | ||
if (!arr) return | ||
else if (arr.some) arr.forEach(iterator) | ||
else { | ||
for (var i = 0; i < arr.length; i++) { | ||
if (iterator.call(null, arr[i], i)) break | ||
} | ||
} | ||
}, | ||
/** | ||
* Invoke handlers in batch process | ||
*/ | ||
batch: function(context, handlers/*, params*/ ) { | ||
var args = this.slice(arguments) | ||
args.shift() | ||
args.shift() | ||
this.each(handlers, function(handler) { | ||
if (handler) handler.apply(context, args) | ||
}) | ||
}, | ||
/** | ||
* binding this context | ||
*/ | ||
bind: function(fn, ctx) { | ||
// native bind is easey to cause maxium call stack | ||
// if (fn.bind) return fn.bind(ctx) | ||
return function () { | ||
fn.apply(ctx, arguments) | ||
} | ||
}, | ||
/** | ||
* Array.slice | ||
*/ | ||
slice: function(array) { | ||
// return Array.prototype.slice.call(array) | ||
var i = array.length | ||
var a = new Array(i) | ||
while(i) { | ||
i -- | ||
a[i] = array[i] | ||
} | ||
return a | ||
}, | ||
/** | ||
* Merge for extObj to obj | ||
**/ | ||
merge: function(obj, extObj) { | ||
this.each(extObj, function(value, key) { | ||
if (extObj.hasOwnProperty(key)) obj[key] = value | ||
}) | ||
return obj | ||
}, | ||
type: function (obj) { | ||
return /\[object ([a-zA-Z]+)\]/.exec(Object.prototype.toString.call(obj))[1].toLowerCase() | ||
}, | ||
missing: function (param, paramName) { | ||
if (!param) throw new Error('Missing param: ' + paramName) | ||
}, | ||
want: function (obj, type) { | ||
if (this.type(obj) != type) throw new Error('Want param ' + obj + ' type is a/an ' + type) | ||
} | ||
} | ||
/** | ||
* Link nodes data structure | ||
@@ -426,8 +339,2 @@ **/ | ||
// AMD/CMD/node/bang | ||
if (typeof exports !== 'undefined') { | ||
if (typeof module !== 'undefined' && module.exports) exports = module.exports = Bootstrap | ||
exports.Chain = Bootstrap | ||
} else this.Chain = Bootstrap | ||
module.exports = Bootstrap |
@@ -0,0 +0,0 @@ ## ChangeLog for: chainjs |
{ | ||
"name": "chainjs", | ||
"version": "0.1.10", | ||
"version": "0.2.0", | ||
"description": "Chainjs call each async function step by step, let async function callback fairily.", | ||
"main": "chain.js", | ||
"scripts": { | ||
"test": "mocha test/test.js", | ||
"cover": "jscoverage chain.js test/tmp/chain.js && npm run mocha-cover", | ||
"mocha-cover": "mocha -r jscoverage --covout=html test/cover.js" | ||
"test": "npm run coverall", | ||
"mocha": "mocha test/test.js", | ||
"coverall": "mocha --require blanket --reporter mocha-lcov-reporter ./test/test.js | ./node_modules/coveralls/bin/coveralls.js", | ||
"cover-html": "mocha --require blanket --reporter html-cov ./test/test.js > coverage.html" | ||
}, | ||
@@ -30,7 +31,18 @@ "repository": { | ||
"devDependencies": { | ||
"blanket": "^1.1.6", | ||
"chai": "^1.10.0", | ||
"colors": "^0.6.2", | ||
"jscoverage": "^0.5.9", | ||
"mocha": "^2.0.1" | ||
"coveralls": "^2.11.2", | ||
"gulp": "^3.9.0", | ||
"gulp-header": "^1.7.1", | ||
"gulp-watch": "^4.3.5", | ||
"gulp-webpack": "^1.5.0", | ||
"mocha": "^2.1.0", | ||
"mocha-lcov-reporter": "0.0.1" | ||
}, | ||
"config": { | ||
"blanket": { | ||
"pattern": "chain.js" | ||
} | ||
} | ||
} |
213
README.md
@@ -5,2 +5,7 @@ chainjs | ||
[![Build Status](https://travis-ci.org/switer/chainjs.svg?branch=master)](https://travis-ci.org/switer/chainjs) | ||
[![Coverage Status](https://coveralls.io/repos/switer/chainjs/badge.svg?branch=master)](https://coveralls.io/r/switer/chainjs?branch=master) | ||
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/switer/chainjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
[![npm version](https://badge.fury.io/js/chainjs.svg)](http://badge.fury.io/js/chainjs) | ||
An asynchronous callback's flow controller, chaining async function callbacks. Async methods calling flow make easy. I use it in node.js server and webapp. | ||
@@ -11,41 +16,85 @@ | ||
```bash | ||
npm install chainjs | ||
npm install chainjs --save | ||
``` | ||
## Usage | ||
:two_men_holding_hands: :two_men_holding_hands: :two_men_holding_hands: | ||
__use in node:__ | ||
**Chainjs** can be used in [node.js](nodejs.org) or browser . Use in node as below: | ||
```javascript | ||
var Chain = require('chainjs') | ||
Chain(function (chain) { | ||
console.log('initialize'); | ||
chain.next('none'); | ||
Chain(function (chain, data) { | ||
// initialize | ||
console.log(data) // --> {name: 'Chainjs'} | ||
chain.next(); | ||
}) | ||
.some(function (chain) { | ||
chain.wait(300, 'then go to next in step 1') | ||
}, function (chain) { | ||
chain.wait(200, 'then go to next in step 2') | ||
}, function (chain) { | ||
chain.wait(100, 'then go to next in step 3') | ||
.then(function (chain) { | ||
chain.nextTo('branchStep') | ||
}) | ||
.then(function (chain, data) { | ||
console.log(data); // --> then go to next in step 3 | ||
chain.next('say hello'); | ||
var count = chain.data('count' || 0) | ||
if (count > 2) { | ||
chain.next('thenStep') | ||
} else { | ||
setTimeout(function () { | ||
chain.data('count', count ++).retry() | ||
}) | ||
} | ||
}) | ||
.branch('branchStep', function (chain) { | ||
chain.next('branchStep') | ||
}) | ||
.then(function (chain, from) { | ||
if (from == 'branchStep') { | ||
// do something | ||
} | ||
chain.next() | ||
}) | ||
.final(function (chain, data) { | ||
console.log(data); // --> say hello | ||
}); | ||
// do something when chain is ending | ||
}) | ||
.start({name: 'Chainjs'}) | ||
``` | ||
:walking: :walking: :walking: :walking: :walking: :walking: | ||
----------------------------------------------------------- | ||
**Look at the diagram of above chain-flow:** | ||
![diagram](http://switer.qiniudn.com/chainjs2.png) | ||
![diagram](http://switer.qiniudn.com/chain-flow.png) | ||
## API | ||
Each step's handler has been passed the `chain` instance as the first argument | ||
Each step's handler has been passed the `chain` instance as the first argument. | ||
### Chain(func, func1, ..., funcN) | ||
Instancing a chain, if arguments is not empty, it will be call .then() with arguments automatically. | ||
If first argument is type of `Array`, that argument will be passed as arguments. | ||
* Global API | ||
- [Chain( *func, ..., funcN* )](#chainfunc--funcn) | ||
- [then( *func, ..., funcN* )](#thenfunc--funcn) | ||
- [some( *func, ..., funcN* )](#somefunc--funcn) | ||
- [each( *func, ..., funcN* )](#eachfunc--funcn) | ||
- [branch( *branchName, func* )](#branchbranchname-func) | ||
- [context( *ctx* )](#contextctx) | ||
- [thunk( *func* )](#thunkfunc) | ||
- [start( *data, ..., dataN* )](#startdata--datan) | ||
- [final( *finalHandler* )](#finalfinalhandler) | ||
* Instance API | ||
- [next( *data, ..., dataN* )](#nextdata--datan) | ||
- [nextTo( *branchName, data, ..., dataN* )](#nexttobranchname-data--datan) | ||
- [wait( *time, data, ..., dataN* )](#waittime-data--datan) | ||
- [end( *data, ..., dataN* )](#enddata--datan) | ||
- [data( *[key] [, value]* )](#datakey--value) | ||
- [retry()](#retry) | ||
- [destroy()](#destroy) | ||
### Chain(func, ..., funcN) | ||
:running: **[API Reference](#api)** | ||
Create a Chain instance. | ||
* if arguments is not empty, it will be call **.then()** with arguments automatically. | ||
* else If first param is type of `Array`, then first param will be passed as arguments. | ||
```javascript | ||
Chain(func /*, func1, ..., funcN*/); | ||
Chain(func /*, ..., funcN*/); | ||
// or | ||
@@ -55,3 +104,6 @@ Chain([func, func1, funcN]) | ||
### .then(func, func1, ..., funcN) | ||
### .then(func, ..., funcN) | ||
:running: **[API Reference](#api)** | ||
Define a chain step, if a then step has multiple functions, it need each function call chain.next() to goto next step. | ||
@@ -63,5 +115,5 @@ ```javascript | ||
```javascript | ||
Chain.then([func1, func2, ..., funcN]) | ||
Chain.then([func, ..., funcN]) | ||
// equal to | ||
Chain.then(func1, func2, ..., funcN) | ||
Chain.then(func, ..., funcN) | ||
``` | ||
@@ -71,2 +123,5 @@ | ||
### .retry() | ||
:running: **[API Reference](#api)** | ||
Call current function once again (use for recursive). | ||
@@ -84,3 +139,6 @@ ```javascript | ||
### .some(func, func1, ..., funcN) | ||
### .some(func, ..., funcN) | ||
:running: **[API Reference](#api)** | ||
Define a chain step, if a then step has multiple functions, it need any function of this step calling chain.next() only once to goto next step. | ||
@@ -111,3 +169,6 @@ ```javascript | ||
### .each(func, func1, ..., funcN) | ||
### .each(func, ..., funcN) | ||
:running: **[API Reference](#api)** | ||
Define a chain step, call each handlers of this step in sequence. In this step, each function call chain.next() to call next function. In orders from left to right of arguments | ||
@@ -124,3 +185,6 @@ ```javascript | ||
### .start(data, data1, ..., dataN) | ||
### .start(data, ..., dataN) | ||
:running: **[API Reference](#api)** | ||
Start running the chain, and could pass data to initial step. | ||
@@ -134,2 +198,5 @@ ```javascript | ||
### .destroy() | ||
:running: **[API Reference](#api)** | ||
Destroy the chain, mark the chain as ending and destroy local variable, but don't calling final funtions. | ||
@@ -146,3 +213,6 @@ | ||
### .next(data, data1, ..., dataN) | ||
### .next(data, ..., dataN) | ||
:running: **[API Reference](#api)** | ||
Go to next step | ||
@@ -156,2 +226,5 @@ ```javascript | ||
### .branch(branchName, func) | ||
:running: **[API Reference](#api)** | ||
Define a branch step, only using `chain.nextTo(branchName)` to goto branch step. | ||
@@ -180,3 +253,6 @@ Call `chain.next()` from last step will skip next branch step. | ||
### .nextTo(branchName, data, data1, ..., dataN) | ||
### .nextTo(branchName, data, ..., dataN) | ||
:running: **[API Reference](#api)** | ||
Go to next branch. | ||
@@ -203,3 +279,6 @@ ```javascript | ||
### .wait(time, data, data1, ..., dataN) | ||
### .wait(time, data, ..., dataN) | ||
:running: **[API Reference](#api)** | ||
Waiting some time then call next step.Just a shortcut of `setTimeout(function () {chain.next()}, time)`. | ||
@@ -211,3 +290,6 @@ ```javascript | ||
### .end(data, data1, ..., dataN) | ||
### .end(data, ..., dataN) | ||
:running: **[API Reference](#api)** | ||
End up chain steps, mark the chain as ending, for cross steps data sharing | ||
@@ -221,2 +303,5 @@ ```javascript | ||
### .final(finalHandler) | ||
:running: **[API Reference](#api)** | ||
Define a final step, witch will be invoke after call chain.end() or all step of this chain is over. | ||
@@ -238,3 +323,6 @@ ```javascript | ||
### .data(savingData) | ||
### .data([key] [, value]) | ||
:running: **[API Reference](#api)** | ||
Saving data in current chain | ||
@@ -257,2 +345,5 @@ ```javascript | ||
### .thunk(func) | ||
:running: **[API Reference](#api)** | ||
Turn a regular node function into chainjs thunk. | ||
@@ -276,2 +367,5 @@ ```javascript | ||
### .context(ctx) | ||
:running: **[API Reference](#api)** | ||
Binding "this" to specified ctx for all functions of each step of current chain. | ||
@@ -289,4 +383,3 @@ ```js | ||
## Testing | ||
Chainjs using [mocha](http://mochajs.org/) for BDD test, run below cli to run testing in nodejs | ||
## Run Testing | ||
```bash | ||
@@ -296,54 +389,2 @@ npm test | ||
## Example | ||
See [using chainjs control business logic flow example](https://github.com/switer/chainjs-flow-control-demo) | ||
```javascript | ||
var Chain = require('chainjs'); | ||
var someStepCount = 0; | ||
var parallelCount = 0; | ||
Chain(function (chain) { | ||
// save param | ||
chain.data('chain:param', 'Chain initial step data'); | ||
chain.next({message: 'Next step'}); | ||
}) | ||
.some(function (chain, param) { | ||
someStepCount ++; | ||
chain.wait(2000, 'step is "some-1"'); | ||
}, function (chain, param) { | ||
someStepCount ++; | ||
chain.wait(1000, 'step is "some-2"'); | ||
}) | ||
.then(function (chain, msg) { | ||
console.log(msg); // step is "some-2 | ||
// Step over when last step has one hander called | ||
console.log(someStepCount); // 1 | ||
chain.next(); | ||
}) | ||
.then(function (chain) { | ||
parallelCount ++; | ||
chain.next(); | ||
}, function (chain) { | ||
parallelCount ++; | ||
chain.next(); | ||
}, function (chain) { | ||
parallelCount ++; | ||
chain.next(); | ||
}) | ||
.then(function (chain) { | ||
// all handlers had been called in last step | ||
console.log(parallelCount); // 3 | ||
chain.end(); | ||
}) | ||
.then(function (chain) { | ||
//prev step had call chain.end(), so this step will be skiped | ||
}) | ||
.final(function (chain) { | ||
var param = chain.data('chain:param'); | ||
console.log(param); // "Chain initial step data" | ||
}) | ||
.context(this) | ||
.start(); // starting chain execute | ||
``` | ||
## Change Log | ||
@@ -350,0 +391,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
28334
9
456
397
10