xref: /expo/packages/@expo/cli/src/utils/profile.ts (revision 8a424beb)
1import chalk from 'chalk';
2
3import { env } from './env';
4import * as Log from '../log';
5
6/**
7 * Wrap a method and profile the time it takes to execute the method using `EXPO_PROFILE`.
8 * Works best with named functions (i.e. not arrow functions).
9 *
10 * @param fn function to profile.
11 * @param functionName optional name of the function to display in the profile output.
12 */
13export function profile<IArgs extends any[], T extends (...args: IArgs) => any>(
14  fn: T,
15  functionName: string = fn.name
16): T {
17  if (!env.EXPO_PROFILE) {
18    return fn;
19  }
20
21  const name = chalk.dim(`⏱  [profile] ${functionName ?? 'unknown'}`);
22
23  return ((...args: IArgs) => {
24    // Start the timer.
25    Log.time(name);
26
27    // Invoke the method.
28    const results = fn(...args);
29
30    // If non-promise then return as-is.
31    if (!(results instanceof Promise)) {
32      Log.timeEnd(name);
33      return results;
34    }
35
36    // Otherwise await to profile after the promise resolves.
37    return new Promise<Awaited<ReturnType<T>>>((resolve, reject) => {
38      results.then(
39        (results) => {
40          resolve(results);
41          Log.timeEnd(name);
42        },
43        (reason) => {
44          reject(reason);
45          Log.timeEnd(name);
46        }
47      );
48    });
49  }) as T;
50}
51