forked from off-topic/apps.apple.com
init commit
This commit is contained in:
116
node_modules/@jet/environment/metrics/parse-and-build-model.js
generated
vendored
Normal file
116
node_modules/@jet/environment/metrics/parse-and-build-model.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.parseAndBuildModel = exports.requestAndBuildModel = void 0;
|
||||
const dependencies_1 = require("../dependencies");
|
||||
const optional_1 = require("../types/optional");
|
||||
const fetch_timing_metrics_builder_1 = require("./fetch-timing-metrics-builder");
|
||||
/**
|
||||
* Returns an object graph guaranteed to have a `FetchTimingMetricsBuilder` object.
|
||||
*
|
||||
* If a `FetchTimingMetricsBuilder` already exists, the same object graph is returned.
|
||||
*
|
||||
* If it doesn't exist, a new object graph is returned, which has a new `FetchTimingMetricsBuilder` added to it.
|
||||
*/
|
||||
function ensureFetchTimingMetricsBuilderExists(objectGraph, errorIfNotFound) {
|
||||
const optionalBuilder = objectGraph.optional(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType);
|
||||
if ((0, optional_1.isSome)(optionalBuilder)) {
|
||||
return objectGraph;
|
||||
}
|
||||
else {
|
||||
if (errorIfNotFound) {
|
||||
throw new Error("Could not find FetchTimingMetricsBuilder in the object graph");
|
||||
}
|
||||
return objectGraph.adding(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType, new fetch_timing_metrics_builder_1.FetchTimingMetricsBuilder());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Orchestrates the flow to make a network request and then build the view model,
|
||||
* capturing timing points around the model building step, and then
|
||||
* adding performance metrics data to the final result.
|
||||
*
|
||||
* **Important**
|
||||
*
|
||||
* When using this method, it is the responsibility of the `requester` to instrument the network times and parsing times
|
||||
* using a `FetchTimingMetricsBuilder` which is in the object graph.
|
||||
*
|
||||
* A simplified implementation of a requester function might look like this:
|
||||
```
|
||||
import * as types from "@jet/environment/types/globals/types"
|
||||
import { fetchTimingMetricsBuilderType } from "@jet/environment/metrics";
|
||||
|
||||
export async function requestFromAPI(request: FetchRequest, objectGraph: ObjectGraph): Promise<MyParsedModel> {
|
||||
const net = inject(types.net, objectGraph);
|
||||
const fetchResponse = await net.fetch(request);
|
||||
const fetchTimingMetricsBuilder = inject(fetchTimingMetricsBuilderType, objectGraph);
|
||||
return fetchTimingMetricsBuilder.measureParsing(fetchResponse, (response) => {
|
||||
const parsedBody = JSON.parse(response.body);
|
||||
return new MyParsedModel(parsedBody);
|
||||
});
|
||||
}
|
||||
```
|
||||
* This approach supports a common pattern in our adopters in which the code that coordinates the fetch of the network request
|
||||
* is tightly coupled to the code which parses the response.
|
||||
*
|
||||
* For an alternative approach which includes orchestrating the parsing step, use `parseAndBuildModel()`.
|
||||
*
|
||||
* @param request - The request object to pass to the `requester` function.
|
||||
* @param objectGraph - Object graph that can be used to pass data to the `requester` and `modelBuilder` steps.
|
||||
* The object graph must contain a `FetchTimingMetricsBuilder` that the `requester` will use to collect network times and parsing times.
|
||||
* @param requester - A function which can make a network request, and return a `ResponseType` which can be used by the `modelBuilder`.
|
||||
* @param modelBuilder - A step that takes the output of the `requester` step, and builds the view model.
|
||||
* This parameter supports both synchronous and asynchronous functions.
|
||||
* @returns The view model.
|
||||
*/
|
||||
async function requestAndBuildModel(request, objectGraph, requester, modelBuilder) {
|
||||
const modifiedObjectGraph = ensureFetchTimingMetricsBuilderExists(objectGraph, true);
|
||||
const response = await requester(request, modifiedObjectGraph);
|
||||
return await constructAndDecorateModel(response, modifiedObjectGraph, modelBuilder);
|
||||
}
|
||||
exports.requestAndBuildModel = requestAndBuildModel;
|
||||
/**
|
||||
* Orchestrates the flow to parse a `FetchResponse` and then build the view model,
|
||||
* adding performance metrics data to the final result.
|
||||
*
|
||||
* Timing points are captured around the parsing and model building steps,
|
||||
* and this is added to the metrics which were returned from the `FetchResponse`.
|
||||
*
|
||||
* When using this method, it is the responsibility of the caller
|
||||
* to perform the network fetch in order to have a `FetchResponse` object.
|
||||
* The parsing logic which transforms the `FetchResponse` object into an intermediate model object
|
||||
* will need to be decoupled so that it can be implemented in the `parser` function.
|
||||
*
|
||||
* @param response - The response from a `Network.fetch()` call.
|
||||
* @param objectGraph - Object graph that can be used to pass data to the `parser` and `renderer` steps.
|
||||
* @param parser - A step that parses a `FetchResponse` to an intermediate model object.
|
||||
* @param modelBuilder - A step that takes the output of the `parser` step, and builds the view model.
|
||||
* This parameter supports both synchronous and asynchronous functions.
|
||||
* @returns The view model.
|
||||
*/
|
||||
async function parseAndBuildModel(response, objectGraph, parser, modelBuilder) {
|
||||
const modifiedObjectGraph = ensureFetchTimingMetricsBuilderExists(objectGraph, false);
|
||||
const fetchTimingMetricsBuilder = (0, dependencies_1.inject)(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType, modifiedObjectGraph);
|
||||
// Add metrics from FetchResponse, and run the parser, capturing timing points.
|
||||
const parsedObject = fetchTimingMetricsBuilder.measureParsing(response, () => {
|
||||
return parser(response, modifiedObjectGraph);
|
||||
});
|
||||
if ((0, optional_1.isNothing)(parsedObject)) {
|
||||
throw new Error("parser function returned null or undefined");
|
||||
}
|
||||
return await constructAndDecorateModel(parsedObject, modifiedObjectGraph, modelBuilder);
|
||||
}
|
||||
exports.parseAndBuildModel = parseAndBuildModel;
|
||||
async function constructAndDecorateModel(parsedObject, objectGraph, modelBuilder) {
|
||||
const fetchTimingMetricsBuilder = (0, dependencies_1.inject)(fetch_timing_metrics_builder_1.fetchTimingMetricsBuilderType, objectGraph);
|
||||
// Run the model builder, capturing timing points.
|
||||
const model = await fetchTimingMetricsBuilder.measureModelConstructionAsync(async () => {
|
||||
const maybePromise = modelBuilder(parsedObject, objectGraph); // The actual model, or a Promise of the model.
|
||||
return await Promise.resolve(maybePromise); // If it was promise, it will await until the promise is resolved.
|
||||
});
|
||||
if ((0, optional_1.isNothing)(model)) {
|
||||
throw new Error("model builder function returned null or undefined");
|
||||
}
|
||||
// Decorate the final output with the metrics data.
|
||||
fetchTimingMetricsBuilder.decorate(model);
|
||||
return model;
|
||||
}
|
||||
//# sourceMappingURL=parse-and-build-model.js.map
|
||||
Reference in New Issue
Block a user