8889841cPK8@[Þ…v#!!index.jsnuW+A„¶'use strict' var nextTick = nextTickArgs process.nextTick(upgrade, 42) // pass 42 and see if upgrade is called with it module.exports = thunky function thunky (fn) { var state = run return thunk function thunk (callback) { state(callback || noop) } function run (callback) { var stack = [callback] state = wait fn(done) function wait (callback) { stack.push(callback) } function done (err) { var args = arguments state = isError(err) ? run : finished while (stack.length) finished(stack.shift()) function finished (callback) { nextTick(apply, callback, args) } } } } function isError (err) { // inlined from util so this works in the browser return Object.prototype.toString.call(err) === '[object Error]' } function noop () {} function apply (callback, args) { callback.apply(null, args) } function upgrade (val) { if (val === 42) nextTick = process.nextTick } function nextTickArgs (fn, a, b) { process.nextTick(function () { fn(a, b) }) } PK8@[$Mç·XX promise.jsnuW+A„¶module.exports = thunkyp function thunkyp (fn) { let running = null return ready function ready () { if (running) return running const p = fn() if (!(p instanceof Promise)) running = Promise.resolve(p) else running = p running.catch(onerror) return running } function onerror () { running = null } } PK8@[Y ™‰ ‰ README.mdnuW+A„¶# thunky Delay the evaluation of a paramless async function and cache the result (see [thunk](http://en.wikipedia.org/wiki/Thunk_%28functional_programming%29)). ``` npm install thunky ``` [![build status](http://img.shields.io/travis/mafintosh/thunky.svg?style=flat)](http://travis-ci.org/mafintosh/thunky) ## Example Let's make a simple function that returns a random number 1 second after it is called for the first time ``` js var thunky = require('thunky') var test = thunky(function (callback) { // the inner function should only accept a callback console.log('waiting 1s and returning random number') setTimeout(function () { callback(Math.random()) }, 1000) }) test(function (num) { // inner function is called the first time we call test console.log(num) // prints random number }) test(function (num) { // subsequent calls waits for the first call to finish and return the same value console.log(num) // prints the same random number as above }) ``` ## Lazy evaluation Thunky makes it easy to implement a lazy evaluation pattern. ``` js var getDb = thunky(function (callback) { db.open(myConnectionString, callback) }) var queryDb = function (query, callback) { getDb(function (err, db) { if (err) return callback(err) db.query(query, callback) }) } queryDb('some query', function (err, result) { ... } ) queryDb('some other query', function (err, result) { ... } ) ``` The first time `getDb` is called it will try do open a connection to the database. Any subsequent calls will just wait for the first call to complete and then call your callback. A nice property of this pattern is that it *easily* allows us to pass any error caused by `getDb` to the `queryDb` callback. ## Error → No caching If the thunk callback is called with an `Error` object as the first argument it will not cache the result ``` js var fails = thunky(function (callback) { console.log('returning an error') callback(new Error('bad stuff')) }) fails(function (err) { // inner function is called console.log(err) }); fails(function (err) { // inner function is called again as it returned an error before console.log(err) }) ``` ## Promise version A promise version is available as well ``` js var thunkyp = require('thunky/promise') var ready = thunkyp(async function () { // ... do async stuff return 42 }) // same semantics as the callback version await ready() ``` ## License MIT PK8@[ ܆§EE .travis.ymlnuW+A„¶language: node_js node_js: - '0.10' - '0.12' - '4.0' - '6.0' PK8@[–vˆ  test.jsnuW+A„¶var tape = require('tape') var thunky = require('./') tape('run only once', function (t) { t.plan(3) var ran = 0 var run = thunky(function (cb) { ran++ cb() }) run(function () { t.same(ran, 1, 'ran once') }) run(function () { t.same(ran, 1, 'ran once') }) run(function () { t.same(ran, 1, 'ran once') }) }) tape('run only once async', function (t) { t.plan(3) var ran = 0 var run = thunky(function (cb) { process.nextTick(function () { ran++ cb() }) }) run(function () { t.same(ran, 1, 'ran once') }) run(function () { t.same(ran, 1, 'ran once') }) run(function () { t.same(ran, 1, 'ran once') }) }) tape('re-run on error', function (t) { t.plan(3) var ran = 0 var run = thunky(function (cb) { ran++ cb(new Error('stop')) }) run(function () { t.same(ran, 1, 'ran once') run(function () { t.same(ran, 2, 'ran once') run(function () { t.same(ran, 3, 'ran once') }) }) }) }) tape('pass arguments', function (t) { t.plan(6) var ran = 0 var run = thunky(function (fn) { ran++ fn({ hello: 'world' }) }) run(function (val) { t.same(ran, 1, 'ran once') t.same(val, { hello: 'world' }) run(function (val) { t.same(ran, 1, 'ran once') t.same(val, { hello: 'world' }) run(function (val) { t.same(ran, 1, 'ran once') t.same(val, { hello: 'world' }) }) }) }) }) tape('callback is optional', function (t) { t.plan(2) var ran = 0 var run = thunky(function (fn) { ran++ fn({ hello: 'world' }) }) run() run(function (val) { t.same(ran, 1, 'ran once') t.same(val, { hello: 'world' }) }) }) tape('always async', function (t) { t.plan(2) var run = thunky(function (cb) { process.nextTick(cb) }) var sync = true run(function () { t.ok(!sync, 'not sync') var innerSync = true run(function () { t.ok(!innerSync, 'not sync') }) innerSync = false }) sync = false }) PK8@[œŽKz77LICENSEnuW+A„¶The MIT License (MIT) Copyright (c) 2018 Mathias Buus Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK8@[äü®ûÅÅ package.jsonnuW+A„¶{ "name": "thunky", "version": "1.1.0", "description": "delay the evaluation of a paramless async function and cache the result", "main": "index.js", "devDependencies": { "standard": "^12.0.1", "tape": "^4.9.1" }, "repository": { "type": "git", "url": "git://github.com/mafintosh/thunky.git" }, "scripts": { "test": "standard && tape test.js" }, "keywords": [ "memo", "thunk", "async", "lazy", "control", "flow", "cache" ], "author": "Mathias Buus Madsen ", "bugs": { "url": "https://github.com/mafintosh/thunky/issues" }, "homepage": "https://github.com/mafintosh/thunky#readme", "license": "MIT" } PK8@[Þ…v#!!index.jsnuW+A„¶PK8@[$Mç·XX Ypromise.jsnuW+A„¶PK8@[Y ™‰ ‰ ëREADME.mdnuW+A„¶PK8@[ ܆§EE ­.travis.ymlnuW+A„¶PK8@[–vˆ  -test.jsnuW+A„¶PK8@[œŽKz77oLICENSEnuW+A„¶PK8@[äü®ûÅÅ Ýpackage.jsonnuW+A„¶PKÞ