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!')
})