@httptoolkit/util 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,11 +6,24 @@ export declare const delay: (ms: number, options?: {
6
6
  * block the process shutdown.
7
7
  */
8
8
  unref?: boolean;
9
- }) => Promise<unknown>;
9
+ }) => Promise<void>;
10
10
  export declare function doWhile<T>(doFn: () => Promise<T>, whileFn: () => Promise<boolean> | boolean): Promise<void>;
11
- export interface Deferred<T> {
11
+ /**
12
+ * A deferred is a promise (you can await it directly) but also exposes the promise
13
+ * explicitly at .promise, and exposes public resolve & reject callbacks for external
14
+ * resolution.
15
+ */
16
+ export interface Deferred<T> extends Promise<T> {
12
17
  resolve: (arg: T) => void;
13
- reject: (e?: Error) => void;
18
+ reject: (e: Error) => void;
14
19
  promise: Promise<T>;
15
20
  }
16
21
  export declare function getDeferred<T = void>(): Deferred<T>;
22
+ /**
23
+ * Wrap a function, so that any parallel calls which happen while the async function
24
+ * is pending return the same value as the first call (so the function is only run
25
+ * once, but the result is shared). This is useful for expensive async functions or
26
+ * race conditions. This ignores arguments completely, and is only applicable for
27
+ * functions that don't need any other input.
28
+ */
29
+ export declare function combineParallelCalls<T>(fn: () => Promise<T>): () => Promise<T>;
package/dist/promises.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDeferred = exports.doWhile = exports.delay = void 0;
3
+ exports.combineParallelCalls = exports.getDeferred = exports.doWhile = exports.delay = void 0;
4
4
  const delay = (ms, options = {}) => new Promise((resolve) => {
5
5
  const timer = setTimeout(resolve, ms);
6
6
  if (options.unref && timer.unref) {
@@ -15,15 +15,32 @@ async function doWhile(doFn, whileFn) {
15
15
  }
16
16
  exports.doWhile = doWhile;
17
17
  function getDeferred() {
18
- let resolve = undefined;
19
- let reject = undefined;
20
- let promise = new Promise((resolveCb, rejectCb) => {
18
+ let resolve;
19
+ let reject;
20
+ const promise = new Promise((resolveCb, rejectCb) => {
21
21
  resolve = resolveCb;
22
22
  reject = rejectCb;
23
23
  });
24
- // TS thinks we're using these before they're assigned, which is why
25
- // we need the undefined types, and the any here.
26
- return { resolve, reject, promise };
24
+ return Object.assign(promise, { resolve, reject, promise });
27
25
  }
28
26
  exports.getDeferred = getDeferred;
27
+ /**
28
+ * Wrap a function, so that any parallel calls which happen while the async function
29
+ * is pending return the same value as the first call (so the function is only run
30
+ * once, but the result is shared). This is useful for expensive async functions or
31
+ * race conditions. This ignores arguments completely, and is only applicable for
32
+ * functions that don't need any other input.
33
+ */
34
+ function combineParallelCalls(fn) {
35
+ let pendingPromise;
36
+ return () => {
37
+ if (pendingPromise === undefined) {
38
+ pendingPromise = fn().finally(() => {
39
+ pendingPromise = undefined;
40
+ });
41
+ }
42
+ return pendingPromise;
43
+ };
44
+ }
45
+ exports.combineParallelCalls = combineParallelCalls;
29
46
  //# sourceMappingURL=promises.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"promises.js","sourceRoot":"","sources":["../src/promises.ts"],"names":[],"mappings":";;;AAEO,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,UAO9B,EAAE,EAAE,EAAE,CACN,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;IACpB,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAEtC,IAAI,OAAO,CAAC,KAAK,IAAK,KAAa,CAAC,KAAK,EAAE;QACtC,KAAa,CAAC,KAAK,EAAE,CAAC;KAC1B;AACL,CAAC,CAAC,CAAC;AAdM,QAAA,KAAK,SAcX;AAEA,KAAK,UAAU,OAAO,CACzB,IAAsB,EACtB,OAAyC;IAEzC,GAAG;QACC,MAAM,IAAI,EAAE,CAAC;KAChB,QAAQ,MAAM,OAAO,EAAE,EAAE;AAC9B,CAAC;AAPD,0BAOC;AAQD,SAAgB,WAAW;IACvB,IAAI,OAAO,GAAmC,SAAS,CAAC;IACxD,IAAI,MAAM,GAAsC,SAAS,CAAC;IAE1D,IAAI,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;QACjD,OAAO,GAAG,SAAS,CAAC;QACpB,MAAM,GAAG,QAAQ,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,oEAAoE;IACpE,iDAAiD;IACjD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAS,CAAC;AAC/C,CAAC;AAZD,kCAYC"}
1
+ {"version":3,"file":"promises.js","sourceRoot":"","sources":["../src/promises.ts"],"names":[],"mappings":";;;AAEO,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,UAO9B,EAAE,EAAE,EAAE,CACN,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;IAC1B,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAEtC,IAAI,OAAO,CAAC,KAAK,IAAK,KAAa,CAAC,KAAK,EAAE;QACtC,KAAa,CAAC,KAAK,EAAE,CAAC;KAC1B;AACL,CAAC,CAAC,CAAC;AAdM,QAAA,KAAK,SAcX;AAEA,KAAK,UAAU,OAAO,CACzB,IAAsB,EACtB,OAAyC;IAEzC,GAAG;QACC,MAAM,IAAI,EAAE,CAAC;KAChB,QAAQ,MAAM,OAAO,EAAE,EAAE;AAC9B,CAAC;AAPD,0BAOC;AAaD,SAAgB,WAAW;IACvB,IAAI,OAA4B,CAAC;IACjC,IAAI,MAA6B,CAAC;IAElC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE;QACnD,OAAO,GAAG,SAAS,CAAC;QACpB,MAAM,GAAG,QAAQ,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;AAChE,CAAC;AAVD,kCAUC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAI,EAAoB;IACxD,IAAI,cAAsC,CAAC;IAE3C,OAAO,GAAG,EAAE;QACR,IAAI,cAAc,KAAK,SAAS,EAAE;YAC9B,cAAc,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBAC/B,cAAc,GAAG,SAAS,CAAC;YAC/B,CAAC,CAAC,CAAC;SACN;QAED,OAAO,cAAc,CAAC;IAC1B,CAAC,CAAC;AACN,CAAC;AAZD,oDAYC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@httptoolkit/util",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "A tiny utility package, sharing JS code widely used across HTTP Toolkit projects",
5
5
  "main": "dist/index.js",
6
6
  "files": [
package/src/promises.ts CHANGED
@@ -8,7 +8,7 @@ export const delay = (ms: number, options: {
8
8
  */
9
9
  unref?: boolean
10
10
  } = {}) =>
11
- new Promise((resolve) => {
11
+ new Promise<void>((resolve) => {
12
12
  const timer = setTimeout(resolve, ms);
13
13
 
14
14
  if (options.unref && (timer as any).unref) {
@@ -25,22 +25,46 @@ export async function doWhile<T>(
25
25
  } while (await whileFn());
26
26
  }
27
27
 
28
- export interface Deferred<T> {
28
+ /**
29
+ * A deferred is a promise (you can await it directly) but also exposes the promise
30
+ * explicitly at .promise, and exposes public resolve & reject callbacks for external
31
+ * resolution.
32
+ */
33
+ export interface Deferred<T> extends Promise<T> {
29
34
  resolve: (arg: T) => void,
30
- reject: (e?: Error) => void,
35
+ reject: (e: Error) => void,
31
36
  promise: Promise<T>
32
37
  }
33
38
 
34
39
  export function getDeferred<T = void>(): Deferred<T> {
35
- let resolve: undefined | ((arg: T) => void) = undefined;
36
- let reject: undefined | ((e?: Error) => void) = undefined;
40
+ let resolve!: ((arg: T) => void);
41
+ let reject!: ((e: Error) => void);
37
42
 
38
- let promise = new Promise<T>((resolveCb, rejectCb) => {
43
+ const promise = new Promise<T>((resolveCb, rejectCb) => {
39
44
  resolve = resolveCb;
40
45
  reject = rejectCb;
41
46
  });
42
47
 
43
- // TS thinks we're using these before they're assigned, which is why
44
- // we need the undefined types, and the any here.
45
- return { resolve, reject, promise } as any;
48
+ return Object.assign(promise, { resolve, reject, promise });
49
+ }
50
+
51
+ /**
52
+ * Wrap a function, so that any parallel calls which happen while the async function
53
+ * is pending return the same value as the first call (so the function is only run
54
+ * once, but the result is shared). This is useful for expensive async functions or
55
+ * race conditions. This ignores arguments completely, and is only applicable for
56
+ * functions that don't need any other input.
57
+ */
58
+ export function combineParallelCalls<T>(fn: () => Promise<T>): () => Promise<T> {
59
+ let pendingPromise: Promise<T> | undefined;
60
+
61
+ return () => {
62
+ if (pendingPromise === undefined) {
63
+ pendingPromise = fn().finally(() => {
64
+ pendingPromise = undefined;
65
+ });
66
+ }
67
+
68
+ return pendingPromise;
69
+ };
46
70
  }