gocsp-thunk
Thunk as a compatible alternative to Promise
Install
npm install gocsp-thunk
Example
var thunk = // create a thunk functionvar thunkFn = // get value from thunk function // convert thunk function into native PromisethunkFn // => 'Hi'
Thunk <=> Promise
It's super easy to convert one to the other.
- do
thunk.from(promise)
to convert promise to thunk function - do
new Promise(thunkFn)
to convert thunk function to promise
Note: you should not use any falsy value (false
, null
, undefined
, 0
, etc) as exception.
Thunk vs Promise
Both thunk and promise are immutable and eager (execution). But thunk has following difference:
- Thunk has no chaining. Unlike
promise.then
,thunkFn(cb)
will NOT return another thunk. Use generator / asyncFn solution to resolve sequential thunks or promises. - Thunk is synchronously. It will callback synchronously whenever data is ready.
- Thunk has no static methods like
.all
,.race
. The equivalence are provided by different modules:.all
: check gocsp-all.race
: check gocsp-select
- Thunk will not catch exception within execute function (from
thunk( executeFn )
).
Error Isolation
The error / exception within cb should not affect others.
The basic policy of error handling within callbacks is not allowing exception. If it does, the error will be caught and re-throw in next tick, which may crash program (add listener to prevent crash, e.g. process.on('uncaughtException', listener)
).
Example:
var thunkFn = // add listener to process to prevent potential crashprocess
It will be troublesome to have sync / async callbacks without error isolation.
Uncaught Exception
Thunk should not swallow exceptions.
If a thunkFn is rejected (e.g. cb(new Error)
) and it has no listeners (callbacks), it will wait until next tick, if still no listeners, it will throw error globally, which probably will crash the program. To prevent crash, you can simply add a noop listener to thunk function or add a listener on process.on('uncaughtException', listener)
.
Example:
// thunk function has no listener, but it is rejected// therefore, it will be re-throw in next tick if there// is no listener at that timevar thunk = var thunkFn =
Add noop listener to prevent crash:
Add listener on process:
process
Sync or Async ?
thunkFunction(cb)
will invoke cb
as soon as data is ready, which means if data is already there, cb
will be invoke immediately / synchronously.
You may notice that this will lead the execution of cb
be indeterministic (aka. zalgo). Then following code will help you to check if it's sync or async.
var called = falseif called // it's sync else // it's async
Also, the coroutine solution will help to determine the order of execution, as following.
var co =
Another problem with sync call is stack overflow when deep recursive sync call. Hope this could be solved by ES6 proper tail call ?
Anyway, you can always convert thunk function to promise if you want to ensure zalgo-free.
thunkFunction
Cancellation
You could cancel the thunk operation
Example:
{ var ref return } var fn =
API Reference
thunk( executor )
Return a thunk function for deferred and asynchronous computations.
Similar to new Promise( executor )
, but executor
only has one argument cb
. Usually, use cb(error)
for
rejecting, and use cb(null, value)
for fulfilling.
Example:
var thunk = var thunkFn = // get value from thunk function.// call `thunkFn` multiple times will get the same result// wrap node style callbacks as thunk
new Promise( thunkFunction )
Convert a thunk function to a Promise instance
// convert to Native Promisevar thunk =
thunk.from( promise )
Convert a Promise instance to a thunk function.
Example:
var thunk = var thunkFn = thunk
thunk.isThunk( object )
Check if an object is thunk function.
Example:
var thunk = thunk // => falsethunk // => falsethunk // => true
thunk.ify( fn )
or thunk.thunkify( fn )
Wrap node style function (callback as last argument) to one which returns a thunk
Example:
var thunk = var readFile = thunk { if err throw err console}
thunk.ifyAll( object )
or thunk.thunkifyAll( object )
Wrap object with node style function as property or in prototype chain into new object with all thunkifed methods.
Example:
var redis = var co = var thunk = var client = thunk
Inspiration
License
MIT