or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-thunkify

Turn callbacks, arrays, generators, generator functions, and promises into a thunk

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/thunkify@2.1.x

To install, run

npx @tessl/cli install tessl/npm-thunkify@2.1.0

0

# Thunkify

1

2

Thunkify converts regular Node.js callback-based functions into thunks, which are functions that accept a callback as their only parameter. This transformation is particularly useful for generator-based flow control systems like co, enabling seamless integration of callback-based APIs with modern async/await patterns.

3

4

## Package Information

5

6

- **Package Name**: thunkify

7

- **Package Type**: npm

8

- **Language**: JavaScript

9

- **Installation**: `npm install thunkify`

10

- **License**: MIT

11

- **Dependencies**: None

12

13

## Core Imports

14

15

```javascript

16

const thunkify = require('thunkify');

17

```

18

19

For ES modules:

20

21

```javascript

22

import thunkify from 'thunkify';

23

```

24

25

## Basic Usage

26

27

```javascript

28

const thunkify = require('thunkify');

29

const fs = require('fs');

30

31

// Convert fs.readFile to a thunk

32

const readFile = thunkify(fs.readFile);

33

34

// Use the thunked function

35

readFile('package.json', 'utf8')(function(err, data) {

36

if (err) throw err;

37

console.log(data);

38

});

39

40

// Works with generator-based flow control

41

function* readFiles() {

42

const data1 = yield readFile('file1.txt', 'utf8');

43

const data2 = yield readFile('file2.txt', 'utf8');

44

return [data1, data2];

45

}

46

```

47

48

## Capabilities

49

50

### Function Conversion

51

52

Converts callback-based functions into thunks for use with generator-based flow control.

53

54

```javascript { .api }

55

/**

56

* Wrap a regular callback function as a thunk

57

* @param {Function} fn - A callback-based function to convert

58

* @returns {Function} A thunk function that accepts arguments and returns a function expecting a callback

59

* @throws {AssertionError} If fn is not a function

60

*/

61

function thunkify(fn): (...args: any[]) => (callback: (err?: Error, ...results: any[]) => void) => void;

62

```

63

64

The `thunkify` function:

65

66

- **Input**: Takes any callback-based function that follows Node.js callback conventions (error-first callback)

67

- **Output**: Returns a thunk function that preserves all original arguments and context

68

- **Context Preservation**: Maintains `this` context when used with object methods

69

- **Error Handling**: Catches synchronous exceptions and forwards them to the callback

70

- **Callback Safety**: Ensures the callback is only called once, ignoring subsequent calls

71

- **Argument Forwarding**: Preserves all function arguments and callback results

72

73

**Usage Examples:**

74

75

```javascript

76

const thunkify = require('thunkify');

77

const fs = require('fs');

78

79

// Basic function thunking

80

const readFile = thunkify(fs.readFile);

81

readFile('package.json', 'utf8')(function(err, data) {

82

console.log(data);

83

});

84

85

// Method thunking with context preservation

86

const user = {

87

name: 'Alice',

88

load: thunkify(function(callback) {

89

// 'this' refers to the user object

90

callback(null, this.name);

91

})

92

};

93

94

user.load()(function(err, name) {

95

console.log(name); // 'Alice'

96

});

97

98

// Error handling - synchronous errors are caught

99

const faultyFn = thunkify(function(callback) {

100

throw new Error('Something went wrong');

101

});

102

103

faultyFn()(function(err) {

104

console.log(err.message); // 'Something went wrong'

105

});

106

107

// Multiple return values are preserved

108

const multiReturn = thunkify(function(a, b, callback) {

109

callback(null, a + b, a * b);

110

});

111

112

multiReturn(5, 3)(function(err, sum, product) {

113

console.log(sum); // 8

114

console.log(product); // 15

115

});

116

```

117

118

## Error Handling

119

120

Thunkify provides comprehensive error handling:

121

122

- **Input Validation**: Throws `AssertionError` if the input is not a function

123

- **Synchronous Errors**: Catches thrown exceptions and passes them to the callback

124

- **Callback Protection**: Prevents multiple callback invocations, ignoring subsequent calls

125

- **Error Forwarding**: Preserves the original error-first callback pattern

126

127

```javascript

128

const thunkify = require('thunkify');

129

130

// Input validation error

131

try {

132

thunkify('not a function');

133

} catch (err) {

134

console.log(err.name); // 'AssertionError'

135

}

136

137

// Synchronous error handling

138

const errorFn = thunkify(function(callback) {

139

throw new Error('Sync error');

140

});

141

142

errorFn()(function(err) {

143

console.log(err.message); // 'Sync error'

144

});

145

```

146

147

## Integration Patterns

148

149

### Generator-based Flow Control

150

151

Thunkify is designed to work seamlessly with generator-based libraries like co:

152

153

```javascript

154

const co = require('co');

155

const thunkify = require('thunkify');

156

const fs = require('fs');

157

158

const readFile = thunkify(fs.readFile);

159

const writeFile = thunkify(fs.writeFile);

160

161

co(function* () {

162

const data = yield readFile('input.txt', 'utf8');

163

const processed = data.toUpperCase();

164

yield writeFile('output.txt', processed, 'utf8');

165

console.log('File processing complete');

166

}).catch(console.error);

167

```

168

169

### Async/Await Compatibility

170

171

While primarily designed for generators, thunked functions can be adapted for async/await:

172

173

```javascript

174

const thunkify = require('thunkify');

175

const { promisify } = require('util');

176

177

// Convert thunk to promise

178

function thunkToPromise(thunk) {

179

return new Promise((resolve, reject) => {

180

thunk((err, ...args) => {

181

if (err) reject(err);

182

else resolve(args.length === 1 ? args[0] : args);

183

});

184

});

185

}

186

187

// Usage with async/await

188

async function example() {

189

const readFile = thunkify(fs.readFile);

190

const data = await thunkToPromise(readFile('package.json', 'utf8'));

191

console.log(data);

192

}

193

```