Skip to content
This repository has been archived by the owner on Aug 17, 2023. It is now read-only.

Commit

Permalink
v0.3.4, support Promise
Browse files Browse the repository at this point in the history
  • Loading branch information
zensh committed Jun 20, 2014
1 parent eca7a94 commit 9a43a34
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 86 deletions.
87 changes: 65 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
Thunk v0.3.2 [![Build Status](https://travis-ci.org/teambition/thunk.png?branch=master)](https://travis-ci.org/teambition/thunk)
Thunk v0.3.4 [![Build Status](https://travis-ci.org/teambition/thunk.png?branch=master)](https://travis-ci.org/teambition/thunk)
====
Thunk! A magical async flow control.

## thunk?
## Thunk?

**`thunk`** 是一个被封装了同步或异步任务的函数,这个函数有唯一一个参数 `callback`。运行 **`thunk`**后,当其封装的任务执行完毕时,任务结果会输入 `callback` 执行。`callback` 的第一个参数是 `error`,没有发生 `error` 则为 `null`
1. **`thunk`** 是一个被封装了同步或异步任务的函数;

**`thunk`** 运行后返回一个新的 **`thunk`**,从而形成链式调用!
2. **`thunk`** 有唯一一个参数 `callback`,是 CPS 函数;

## Async Chain
3. **`thunk`** 运行后返回新的 **`thunk`** 函数,形成链式调用;

4. **`thunk`** 自身执行完毕后,结果进入 `callback` 运行;

5. `callback` 的返回值如果是 **`thunk`** 函数,则等该 **`thunk`** 执行完毕将结果输入新 **`thunk`** 函数运行;如果是其它值,则当做正确结果进入新的 **`thunk`** 函数运行;

## Async Chain By Thunk

Thunk(function (callback) {
// ...
callback(null, value)
})(function(error, value){
// ...
return value
})(function(error, value){
// ...
return Thunk(function (callback) { // nest thunk
// ...
callback(null, value)
})(function (error, value) {

})
})(function(error, value){
// ...
})

## Demo1
## Demo

var Thunkjs = require('../thunk.js');
var fs = require('fs');
Expand All @@ -36,7 +50,7 @@ Thunk! A magical async flow control.
console.error('This should not run!', error);
});

## Demo2
// No `Maximum call stack size exceeded` error in 1000000 sync series

var Thunk = require('../thunk.js')();
var thunk = Thunk(0);
Expand All @@ -51,7 +65,7 @@ Thunk! A magical async flow control.
}

thunk(function (error, value) {
console.log(error, value); // null, 1000000
console.log(error, value); // null 1000000
console.timeEnd('Thunk_series'); // ~1468ms
});

Expand All @@ -63,20 +77,20 @@ Thunk! A magical async flow control.

`Thunk` 生成器函数,生成一个带作用域的 `Thunk` 主函数,作用域是指该 `Thunk` 直接或间接生成的所有 `thunk` 函数的内部运行环境。

生成基本形式的 `Thunk`,任何异常会输入到下一个 `thunk` 函数:
1. 生成基本形式的 `Thunk`,任何异常会输入到下一个 `thunk` 函数:

var Thunk = Thunkjs();
var Thunk = Thunkjs();

生成有 `onerror` 监听的 `Thunk`,该 `Thunk` 作用域内的任何异常都可被 `onerror` 捕捉,而不会进入下一个 `thunk` 函数:
2. 生成有 `onerror` 监听的 `Thunk`,该 `Thunk` 作用域内的任何异常都可被 `onerror` 捕捉,而不会进入下一个 `thunk` 函数:

var Thunk = Thunkjs(function (error) { console.error(error); });
var Thunk = Thunkjs(function (error) { console.error(error); });

生成有 `onerror` 监听和 `debug` 监听的 `Thunk``onerror` 同上,该 `Thunk` 作用域内的所有运行结果都会先进入 `debug` 函数,然后再进入下一个 `thunk` 函数:
3. 生成有 `onerror` 监听和 `debug` 监听的 `Thunk``onerror` 同上,该 `Thunk` 作用域内的所有运行结果都会先进入 `debug` 函数,然后再进入下一个 `thunk` 函数:

var Thunk = Thunkjs({
onerror: function (error) { console.error(error); },
debug: function () { console.log.apply(console, arguments); }
});
var Thunk = Thunkjs({
onerror: function (error) { console.error(error); },
debug: function () { console.log.apply(console, arguments); }
});

拥有不同作用域的多个 `Thunk` 主函数组合成复杂逻辑体时,各自的作用域仍然相互隔离,也就是说 `onerror` 监听和 `debug` 监听不会在其它作用域运行。

Expand All @@ -97,27 +111,56 @@ Thunk! A magical async flow control.
Thunk(function (callback) {
callback(null, 1)
})(function (error, value) {
console.log(error, value); // null, 1
console.log(error, value); // null 1
});

2. promise,promise的结果进入新的 `thunk` 函数

var promise = Promise.resolve(1);

Thunk(promise)(function (error, value) {
console.log(error, value); // null 1
});

2. 自带 `thunk` 方法的对象

var then = Thenjs(1); // then.thunk is a thunk function

Thunk(then)(function (error, value) {
console.log(error, value); // null 1
});

3. 其它值,当作有效结果进入新的 `thunk` 函数

Thunk(1)(function (error, value) {
console.log(error, value); // null, 1
console.log(error, value); // null 1
});

Thunk([1, 2, 3])(function (error, value) {
console.log(error, value); // null [1, 2, 3]
});


### Thunk.all(array)
### Thunk.all(obj)

返回一个新的 `thunk` 函数。

`array` 是一个包含多个 `thunk` 函数的数组,并发执行各个 `thunk` 函数,全部执行完毕后其结果形成一个新数组(顺序与原数组对应),输入到返回的新`thunk` 函数。
`obj` 是一个包含多个 `thunk` 函数的数组或对象,并发执行各个 `thunk` 函数,全部执行完毕后其结果形成一个新数组(顺序与原数组对应)或对象,输入到返回的新`thunk` 函数。

Thunk.all([
Thunk(0),
Thunk(1),
2,
Thunk(function (callback) { callback(null, [3]); })
])(function (error, value) {
console.log(error, value); // null, [0, 1, 2, [3]]
console.log(error, value); // null [0, 1, 2, [3]]
});

Thunk.all({
a: Thunk(0),
b: Thunk(1),
c: 2,
d: Thunk(function (callback) { callback(null, [3]); })
})(function (error, value) {
console.log(error, value); // null {a: 0, b: 1, c: 2, d: [3]}
});
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "thunk",
"description": "Thunk! A magical async flow control.",
"main": "thunk.js",
"version": "0.3.3",
"version": "0.3.4",
"homepage": "https://github.com/teambition/thunk",
"authors": [
"Yan Qing <admin@zensh.com>"
Expand Down
2 changes: 1 addition & 1 deletion examples/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var thunk = Thunk(0);
function callback(error, value) {
return ++value;
}
// No `Maximum call stack size exceeded` error in sync series
// No `Maximum call stack size exceeded` error in 1000000 sync series
console.time('Thunk_series');
for (var i = 0; i < 1000000; i++) {
thunk = thunk(callback);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"author": {
"name": "zensh"
},
"version": "0.3.3",
"version": "0.3.4",
"main": "thunk.js",
"repository": {
"type": "git",
Expand Down
122 changes: 101 additions & 21 deletions test/nodeunit.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
'use strict';
/*global module, process*/
/*global module, process, Promise, noneFn*/

var Thunk = require('../thunk.js'),
var Thunkjs = require('../thunk.js'),
x = {};

exports.thunk1 = function (test) {
// 测试 thunk 组合
var thunk = Thunk();
var thunk1 = thunk(1);
var Thunk = Thunkjs();
var thunk1 = Thunk(1);
test.strictEqual(thunk1._isThunk, true);
var thunk2 = thunk1(function (error, value) {
test.strictEqual(error, null);
Expand All @@ -18,7 +18,7 @@ exports.thunk1 = function (test) {
var thunk3 = thunk2(function (error, value) {
test.strictEqual(error, null);
test.strictEqual(value, 2);
return thunk(function (callback) {
return Thunk(function (callback) {
setImmediate(function () {
callback(null, x);
});
Expand All @@ -28,15 +28,15 @@ exports.thunk1 = function (test) {
thunk3(function (error, value) {
test.strictEqual(error, null);
test.strictEqual(value, x);
return thunk(function (callback) {
return Thunk(function (callback) {
setImmediate(function () {
callback(false, true);
});
});
})(function (error, value) {
test.strictEqual(error, false);
test.strictEqual(value, undefined);
return thunk(function (callback) {
return Thunk(function (callback) {
callback(null, 1, 2, 3, x);
});
})(function (error, value1, value2, value3, value4) {
Expand All @@ -46,14 +46,14 @@ exports.thunk1 = function (test) {
test.strictEqual(value2, 2);
test.strictEqual(value3, 3);
test.strictEqual(value4, x);
return thunk(function (callback) {
return Thunk(function (callback) {
setImmediate(function () {callback(null, 1);});
})(function (error, value) {
test.strictEqual(value, 1);
return value * 2;
})(function (error, value) {
test.strictEqual(value, 2);
return thunk(function (callback) {
return Thunk(function (callback) {
setImmediate(function () {callback(null, value * 2);});
});
})(function (error, value) {
Expand All @@ -62,33 +62,113 @@ exports.thunk1 = function (test) {
});
})(function (error, value) {
test.strictEqual(value, 8);
return thunk(thunk(value * 2));
return Thunk(Thunk(value * 2));
})(function (error, value) {
test.strictEqual(value, 16);
return thunk.all([
return Thunk.all([]);
})(function (error, value) {
test.deepEqual(value, []);
return Thunk.all([1, 2, 3, 4, 5]);
})(function (error, value) {
test.deepEqual(value, [1, 2, 3, 4, 5]);
return Thunk.all([
0,
thunk(1),
thunk(thunk(2)),
thunk(function (callback) {
Thunk(1),
Thunk(Thunk(2)),
Thunk(function (callback) {
setImmediate(function () { callback(null, 3); });
}),
thunk(thunk(function (callback) {
Thunk(Thunk(function (callback) {
setImmediate(function () { callback(null, 4); });
})),
[5]
]);
})(function (error, value) {
test.deepEqual(value, [0, 1, 2, 3, 4, [5]]);
return Thunk.all([
0,
Thunk(1),
Thunk(Thunk(2)),
Thunk(function (callback) {
setImmediate(function () { callback(null, 3); });
}),
Thunk(function (callback) {
noneFn();
}),
[5]
])(function (error, value) {
console.error(error);
test.strictEqual(error instanceof Error, true);
test.strictEqual(value, undefined);
return Thunk.all(1);
})(function (error, value) {
console.error(error);
test.strictEqual(error instanceof Error, true);
test.strictEqual(value, undefined);
return Thunk.all(x);
});
})(function (error, value) {
test.notStrictEqual(value, x);
test.deepEqual(value, {});
return Thunk.all({a: 1, b: 2, c: 3, d: 4, e: [5]});
})(function (error, value) {
test.deepEqual(value, {a: 1, b: 2, c: 3, d: 4, e: [5]});
return Thunk.all({
a: 1,
b: Thunk(2),
c: Thunk(Thunk(3)),
d: Thunk(function (callback) {
setImmediate(function () { callback(null, 4); });
}),
e: [5]
});
})(function (error, value) {
test.deepEqual(value, {a: 1, b: 2, c: 3, d: 4, e: [5]});
return Thunk.all({
a: 1,
b: Thunk(2),
c: Thunk(Thunk(3)),
d: Thunk(function (callback) {
noneFn();
}),
e: [5]
})(function (error, value) {
console.error(error);
test.strictEqual(error instanceof Error, true);
test.strictEqual(value, undefined);
});
})(function (error, value) {
if (typeof Promise === 'function') {
return Thunk(Promise.resolve(1))(function (error, value) {
test.strictEqual(error, null);
test.strictEqual(value, 1);
return Thunk(Promise.reject(false));
})(function (error, value) {
test.strictEqual(error, false);
test.strictEqual(value, undefined);
var promise = new Promise(function (resolve, rejecct) {
setImmediate(function () { resolve(x); });
});
return Thunk(promise);
})(function (error, value) {
test.strictEqual(value, x);
return 'TEST SUCCESS!';
});
} else {
return 'TEST SUCCESS!';
}
})(function (error, value) {
test.strictEqual(value, 'TEST SUCCESS!');
test.done();
});
};
exports.thunk2 = function (test) {
// 测试 thunk 作用域内的 debug 模式和异常处理
test.notStrictEqual(Thunk(), Thunk());
var thunk = Thunk();
thunk()(function (error) {
test.notStrictEqual(Thunkjs(), Thunkjs());
var Thunk = Thunkjs();
Thunk()(function (error) {
var _error, e = {};
var thunk1 = Thunk(function (error) {
var thunk1 = Thunkjs(function (error) {
_error = error;
});
thunk1(function (callback) {
Expand All @@ -102,7 +182,7 @@ exports.thunk2 = function (test) {
test.strictEqual(error, null);
test.strictEqual(arguments.length, 1);
var _error, _debug, e = {};
var thunk1 = Thunk({
var thunk1 = Thunkjs({
onerror: function (error) {
_error = error;
},
Expand All @@ -125,7 +205,7 @@ exports.thunk2 = function (test) {
test.strictEqual(_error, e);
test.strictEqual(_debug[0], e);
test.strictEqual(_debug.length, 2);
return thunk(function (callback) {
return Thunk(function (callback) {
callback(1, 2, 3);
});
})(function (error) {
Expand Down
Loading

0 comments on commit 9a43a34

Please sign in to comment.