1.2 KB37 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8// See https://advancedweb.hu/the-async-lazy-initializer-pattern-in-javascript/
9
10/**
11 * Because Promises are eager in JavaScript, we need to introduce an extra layer
12 * to lazily invoke an async operation. lazyInit() takes a function that
13 * represents the async operation, but does not call it until the function
14 * returned by lazyInit() itself is called. Note that lazyInit() is idempotent:
15 * once it is called, it will always return the original Promise created by
16 * calling the async operation.
17 *
18 * ```
19 * // Note getObj is a *function*, not a *Promise*.
20 * const getObj = lazyInit(async () => {
21 * const value = await expensiveOperation();
22 * return value + 1;
23 * });
24 *
25 * ...
26 *
27 * // expensiveObjCreation() will not be called until getObj() is called, and if
28 * // it is called, it will only be called once.
29 * const objRef1 = await getObj();
30 * const objRef2 = await getObj();
31 * ```
32 */
33export default function lazyInit<T>(init: () => Promise<T>): () => Promise<T> {
34 let promise: Promise<T> | null = null;
35 return () => (promise = promise ?? init());
36}
37