A small and magical composer for all JavaScript asynchronous.
-
thunk
是一个被封装了同步或异步任务的函数; -
thunk
有唯一一个参数callback
,是 CPS 函数; -
thunk
运行后返回新的thunk
函数,形成链式调用; -
thunk
自身执行完毕后,结果进入callback
运行; -
callback
的返回值如果是thunk
函数,则等该thunk
执行完毕将结果输入新thunk
函数运行;如果是其它值,则当做正确结果进入新的thunk
函数运行;
const thunks = require('thunks')
母函数,生成一个带作用域的 thunk
生成器,作用域是指该 thunk
生成器直接或间接生成的所有子 thunk 函数的内部运行环境。
- 生成基本形式的
thunk
,任何异常会输入到下一个子 thunk 函数:
const thunk = thunks()
- 生成有
onerror
监听的thunk
,该thunk
作用域内的任何异常都可被onerror
捕捉,而不会进入下一个 子 thunk 函数,除非onerror
返回true
:
const thunk = thunks(function (error) { console.error(error) })
- 生成有
onerror
监听,onstop
监听和debug
监听的thunk
,onerror
同上,该thunk
作用域内的所有运行结果都会先进入debug
函数,然后再进入下一个子 thunk 函数:
const thunk = thunks({
onstop: function (sig) { console.log(sig) },
onerror: function (error) { console.error(error) },
debug: function () { console.log.apply(console, arguments) }
})
拥有不同作用域的多个 thunk
生成器组合成复杂逻辑体时,各自的作用域仍然相互隔离,也就是说 onerror
监听和 debug
监听不会在其它作用域运行。
生成器,生成一个新的子 thunk 函数。
其中 thunkable
可以是:
- 子 thunk 函数,执行该函数,结果进入新的子 thunk 函数
let thunk1 = thunk(1)
let thunk2 = thunk(thunk1) // thunk2 等效于 thunk1
- function (callback) {},执行该函数,callback收集结果进入新的子 thunk 函数
thunk(function (callback) {
callback(null, 1)
})(function (error, value) {
console.log(error, value) // null 1
})
- promise,promise的结果进入新的子 thunk 函数
let promise = Promise.resolve(1)
thunk(promise)(function (error, value) {
console.log(error, value) // null 1
})
- 自带
toThunk
方法的对象
let then = Thenjs(1) // then.toThunk() 能转换成 thunk 形式的函数,也能用于 `co`
thunk(then)(function (error, value) {
console.log(error, value) // null 1
})
- Generator 或 Generator Function, 与
co
类似,但更进一步,可以yield
任何值,可以形成链式调用
thunk(function * () {
var x = yield 10
return 2 * x
})(function * (error, res) {
console.log(error, res) // null, 20
return yield [1, 2, thunk(3)]
})(function * (error, res) {
console.log(error, res) // null, [1, 2, 3]
return yield {
name: 'test',
value: thunk(1)
}
})(function (error, res) {
console.log(error, res) // null, {name: 'test', value: 1}
})
- async/await function
thunk(async function () {
console.log(await Promise.resolve('await promise in a async function'))
try {
await new Promise((resolve, reject) => {
setTimeout(() => reject('catch promise error in async function'), 1000)
})
} catch (err) {
console.log(err)
}
})(function * () {
console.log(yield async () => 'yield a async function in generator function')
})()
- 其它值,当作有效结果进入新的子 thunk 函数
thunk(1)(function (error, value) {
console.log(error, value) // null 1
})
thunk([1, 2, 3])(function (error, value) {
console.log(error, value) // null [1, 2, 3]
})
还可以这样运行(this):
thunk.call({x: 123}, 456)(function (error, value) {
console.log(error, this.x, value) // null 123 456
return 'thunk!'
})(function (error, value) {
console.log(error, this.x, value) // null 123 'thunk!'
})
返回一个新的子 thunk 函数。
obj
是一个包含多个子 thunk 函数或 promise 的数组或对象,并发执行各个子 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]]
})
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]}
})
还可以这样运行(this):
thunk.all.call({x: [1, 2, 3]}, [4, 5, 6])(function (error, value) {
console.log(error, this.x, value) // null [1, 2, 3] [4, 5, 6]
return 'thunk!'
})(function (error, value) {
console.log(error, this.x, value) // null [1, 2, 3] 'thunk!'
})
返回一个新的子 thunk 函数。
thunkX
可以是任何值,thunk.seq
会按照顺序将其转换子 thunk 函数 并逐步执行,全部执行完毕后其结果形成一个新数组(顺序与原数组对应),输入到返回的新子 thunk 函数。
thunk.seq([
function (callback) {
setTimeout(function () {
callback(null, 'a', 'b')
}, 100)
},
thunk(function (callback) {
callback(null, 'c')
}),
[thunk('d'), thunk('e')], // thunk in array will be excuted in parallel
function (callback) {
should(flag).be.eql([true, true])
flag[2] = true
callback(null, 'f')
}
])(function (error, value) {
console.log(error, value) // null [['a', 'b'], 'c', ['d', 'e'], 'f']
})
or
thunk.seq(
function (callback) {
setTimeout(function () {
callback(null, 'a', 'b')
}, 100)
},
thunk(function (callback) {
callback(null, 'c')
}),
[thunk('d'), thunk('e')], // thunk in array will be excuted in parallel
function (callback) {
should(flag).be.eql([true, true])
flag[2] = true
callback(null, 'f')
}
)(function (error, value) {
console.log(error, value) // null [['a', 'b'], 'c', ['d', 'e'], 'f']
})
还可以这样运行(this):
thunk.seq.call({x: [1, 2, 3]}, 4, 5, 6)(function (error, value) {
console.log(error, this.x, value) // null [1, 2, 3] [4, 5, 6]
return 'thunk!'
})(function (error, value) {
console.log(error, this.x, value) // null [1, 2, 3] 'thunk!'
})
返回一个新的子 thunk 函数。迭代数组所有子 thunk 函数最先完成的运算结果会传入其中,无论正确或错误。
返回一个新函数,运行该函数会返回子 thunk 函数。
将带 callback 参数的 nodejs 风格的函数 fn
转换成一个新的函数,新函数不再接收 callback
,其输出为子 thunk 函数。
const thunk = require('thunks')()
const fs = require('fs')
const fsStat = thunk.thunkify(fs.stat)
fsStat('thunks.js')(function (error, result) {
console.log('thunks.js: ', result)
})
fsStat('.gitignore')(function (error, result) {
console.log('.gitignore: ', result)
})
还可以这样运行(this):
let obj = {a: 8}
function run (x, callback) {
//...
callback(null, this.a * x)
}
let run = thunk.thunkify.call(obj, run)
run(1)(function (error, result) {
console.log('run 1: ', result)
})
run(2)(function (error, result) {
console.log('run 2: ', result)
})
lift
概念来自于 Haskell,它将一个同步函数转化成一个异步函数。该异步函数接受 thunkable
参数,等所有参数求得真实值后,再按照原函数逻辑运行。该异步函数返回子 thunk 函数。
const thunk = require('thunks')()
function calculator (a, b, c) {
return (a + b + c) * 10
}
const calculatorT = thunk.lift(calculator)
let value1 = thunk(2)
let value2 = Promise.resolve(3)
calculatorT(value1, value2, 5)(function (error, result) {
console.log(result) // 100
})
You may also write code with this
:
const calculatorT = thunk.lift.call(context, calculator)
将 thunkable
值转换成一个可以持久化的 thunk 函数,可以无限次运行该函数而取得其值。
const thunk = require('thunks')()
let persistThunk = thunk.persist(thunk(x))
persistThunk(function (error, result) {
console.log(1, result) // x
return persistThunk(function (error, result) {
console.log(2, result) // x
return persistThunk
})
})(function (error, result) {
console.log(3, result) // x
})
You may also write code with this
:
let persistThunk = thunk.persist.call(context, thunkable)
返回一个新的子 thunk 函数,该子 thunk 函数的主体将会在 delay
毫秒之后运行。
console.log('thunk.delay 500: ', Date.now())
thunk.delay(500)(function () {
console.log('thunk.delay 1000: ', Date.now())
return thunk.delay(1000)
})(function () {
console.log('thunk.delay end: ', Date.now())
})
还可以这样运行(this):
console.log('thunk.delay start: ', Date.now())
thunk.delay.call(this, 1000)(function () {
console.log('thunk.delay end: ', Date.now())
})
终止 thunk
函数组合体的运行,类似于 Promise
的 cancelable
(ES6 没有定义,原生 Promise 也未实现)。运行 thunk.stop
将抛出一个终止信号对象。终止信号能被作用域的 onstop
捕获,但也能被 try catch
捕获并屏蔽。
终止信号拥有 message
、特殊的 code
和 status === 19
(POSIX signal SIGSTOP)。
const thunk = require('thunks')({
debug: function (res) {
if (res) console.log(res) // { [Error: Stop now!] code: {}, status: 19 }
}
})
thunk(function (callback) {
thunk.stop('Stop now!')
console.log('It will not be run!')
})(function (error, value) {
console.log('It will not be run!')
})
thunk.delay(100)(function () {
console.log('Hello')
return thunk.delay(100)(function () {
thunk.stop('Stop now!')
console.log('It will not be run!')
})
})(function (error, value) {
console.log('It will not be run!')
})