request = (dependencies, context) => {
    const computedName = computableArtifact.name;

    // Guard against missing properties. Optional properties must be passed as null - if missing or
    // undefined, throw an error.
    for (const key of keys || []) {
      if (dependencies && typeof dependencies === 'object' && dependencies[key] === undefined) {
        // eslint-disable-next-line max-len
        const err = new Error(`missing required key "${String(key)}" for computed artifact ${computableArtifact.name}`);
        if (isUnderTest) {
          throw err;
        } else {
          // For now, simply log in production.
          log.error(`lh:computed:${computedName}`, err);
        }
      }
    }

    const pickedDependencies = keys ?
      Object.fromEntries(keys.map(key => [key, dependencies[key]])) :
      dependencies;

    // NOTE: break immutability solely for this caching-controller function.
    const computedCache = /** @type {Map<string, ArbitraryEqualityMap>} */ (context.computedCache);

    const cache = computedCache.get(computedName) || new ArbitraryEqualityMap();
    computedCache.set(computedName, cache);

    /** @type {ReturnType<C['compute_']>|undefined} */
    const computed = cache.get(pickedDependencies);
    if (computed) {
      return computed;
    }

    const status = {msg: `Computing artifact: ${computedName}`, id: `lh:computed:${computedName}`};
    log.time(status, 'verbose');

    const artifactPromise = /** @type {ReturnType<C['compute_']>} */
        (computableArtifact.compute_(pickedDependencies, context));
    cache.set(pickedDependencies, artifactPromise);

    artifactPromise.then(() => log.timeEnd(status)).catch(() => log.timeEnd(status));

    return artifactPromise;
  }
Return an automatically cached result from the computed artifact.
@param {LH.Util.FirstParamType<C['compute_']>} dependencies
@param {LH.Artifacts.ComputedContext} context
@return {ReturnType<C['compute_']>}