Skip to content

Commit cf19ced

Browse files
authored
fix: revert "feat: remove nodeify* functions as obsolete (#52)" (#53)
This reverts commit b50a289.
1 parent 7e87dff commit cf19ced

File tree

3 files changed

+132
-2
lines changed

3 files changed

+132
-2
lines changed

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,44 @@ console.log(newItems); // [2, 4];
102102
By default, `asyncmap` and `asyncfilter` run their operations in parallel; you
103103
can pass `false` as a third argument to make sure it happens serially.
104104

105+
### Nodeify
106+
107+
Export async functions (Promises) and import this with your ES5 code to use it
108+
with Node.
109+
110+
```js
111+
var asyncbox = require('asyncbox')
112+
, sleep = asyncbox.sleep
113+
, nodeify = asyncbox.nodeify;
114+
115+
nodeify(sleep(1000), function (err, timer) {
116+
console.log(err); // null
117+
console.log(timer); // timer obj
118+
});
119+
```
120+
121+
### nodeifyAll
122+
123+
If you have a whole library you want to export nodeified versions of, it's pretty easy:
124+
125+
```js
126+
import { nodeifyAll } from 'asyncbox';
127+
128+
async function foo () { ... }
129+
async function bar () { ... }
130+
let cb = nodeifyAll({foo, bar});
131+
export { foo, bar, cb };
132+
```
133+
134+
Then in my ES5 script I can do:
135+
136+
```js
137+
var myLib = require('mylib').cb;
138+
139+
myLib.foo(function (err) { ... });
140+
myLib.bar(function (err) { ... });
141+
```
142+
105143
### waitForCondition
106144

107145
Takes a condition (a function returning a boolean or boolean promise),

lib/asyncbox.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import B from 'bluebird';
22
import _ from 'lodash';
3-
import type {LongSleepOptions, WaitForConditionOptions} from './types.js';
3+
import type {
4+
LongSleepOptions,
5+
WaitForConditionOptions,
6+
} from './types.js';
47

58
const LONG_SLEEP_THRESHOLD = 5000; // anything over 5000ms will turn into a spin
69

@@ -26,7 +29,11 @@ export async function sleep(ms: number): Promise<void> {
2629
*/
2730
export async function longSleep(
2831
ms: number,
29-
{thresholdMs = LONG_SLEEP_THRESHOLD, intervalMs = 1000, progressCb = null}: LongSleepOptions = {},
32+
{
33+
thresholdMs = LONG_SLEEP_THRESHOLD,
34+
intervalMs = 1000,
35+
progressCb = null,
36+
}: LongSleepOptions = {},
3037
): Promise<void> {
3138
if (ms < thresholdMs) {
3239
return await sleep(ms);
@@ -108,6 +115,35 @@ export async function retryInterval<T = any>(
108115

109116
export const parallel = B.all;
110117

118+
/**
119+
* Export async functions (Promises) and import this with your ES5 code to use
120+
* it with Node.
121+
* @param promisey - A Promise or promise-like value to convert to a callback
122+
* @param cb - The callback function to call with the result or error
123+
*/
124+
// eslint-disable-next-line promise/prefer-await-to-callbacks
125+
export function nodeify<R = any>(promisey: any, cb: (err: any, value?: R) => void): Promise<R> {
126+
return B.resolve(promisey).nodeify(cb);
127+
}
128+
129+
/**
130+
* Node-ify an entire object of `Promise`-returning functions
131+
* @param promiseyMap - An object containing functions that return Promises
132+
*/
133+
export function nodeifyAll<T extends Record<string, (...args: any[]) => any>>(
134+
promiseyMap: T,
135+
): Record<string, (...args: any[]) => void> {
136+
const cbMap: Record<string, (...args: any[]) => void> = {};
137+
for (const [name, fn] of _.toPairs(promiseyMap)) {
138+
cbMap[name] = function (...args: any[]) {
139+
const _cb = args.slice(-1)[0] as (err: any, ...values: any[]) => void;
140+
const fnArgs = args.slice(0, -1);
141+
nodeify(fn(...fnArgs), _cb);
142+
};
143+
}
144+
return cbMap;
145+
}
146+
111147
/**
112148
* Fire and forget async function execution
113149
* @param fn - The function to execute asynchronously

test/asyncbox-specs.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
longSleep,
66
retry,
77
retryInterval,
8+
nodeify,
9+
nodeifyAll,
810
parallel,
911
asyncmap,
1012
asyncfilter,
@@ -173,6 +175,60 @@ describe('retry', function () {
173175
});
174176
});
175177

178+
describe('nodeifyAll', function () {
179+
const asyncFn = async function (val: string): Promise<string> {
180+
await sleep(15);
181+
return val;
182+
};
183+
const asyncFn2 = async function (val: string): Promise<string[]> {
184+
await sleep(15);
185+
return [val, val + val];
186+
};
187+
const badAsyncFn = async function (): Promise<never> {
188+
await sleep(15);
189+
throw new Error('boo');
190+
};
191+
const cbMap = nodeifyAll({asyncFn, asyncFn2, badAsyncFn});
192+
it('should turn async functions into nodey things', function (done) {
193+
const start = Date.now();
194+
nodeify(asyncFn('foo'), function (err: Error | null, val?: string, val2?: string) { // eslint-disable-line promise/prefer-await-to-callbacks
195+
expect(err).to.not.exist;
196+
expect(val2).to.not.exist;
197+
expect(val!).to.equal('foo');
198+
expect(Date.now() - start).to.be.at.least(14);
199+
done();
200+
});
201+
});
202+
it('should turn async functions into nodey things via nodeifyAll', function (done) {
203+
const start = Date.now();
204+
cbMap.asyncFn('foo', function (err: Error | null, val?: string, val2?: string) { // eslint-disable-line promise/prefer-await-to-callbacks
205+
expect(err).to.not.exist;
206+
expect(val2).to.not.exist;
207+
expect(val!).to.equal('foo');
208+
expect(Date.now() - start).to.be.at.least(14);
209+
done();
210+
});
211+
});
212+
it('should turn async functions into nodey things with mult params', function (done) {
213+
const start = Date.now();
214+
nodeify(asyncFn2('foo'), function (err: Error | null, val?: string[]) { // eslint-disable-line promise/prefer-await-to-callbacks
215+
expect(err).to.not.exist;
216+
expect(val!).to.eql(['foo', 'foofoo']);
217+
expect(Date.now() - start).to.be.at.least(14);
218+
done();
219+
});
220+
});
221+
it('should handle errors correctly', function (done) {
222+
const start = Date.now();
223+
nodeify(badAsyncFn(), function (err: Error | null, val?: string) { // eslint-disable-line promise/prefer-await-to-callbacks
224+
expect(val).to.not.exist;
225+
expect(err!.message).to.equal('boo');
226+
expect(Date.now() - start).to.be.at.least(14);
227+
done();
228+
});
229+
});
230+
});
231+
176232
describe('parallel', function () {
177233
const asyncFn = async function (val: number): Promise<number> {
178234
await sleep(50);

0 commit comments

Comments
 (0)