mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
* [Flight] Align Chunks with Thenable used with experimental_use Use the field names used by the Thenable data structure passed to use(). These are considered public in this model. This adds another field since we use a separate field name for "reason". * Implement Thenable Protocol on Chunks This doesn't just ping but resolves/rejects with the value. * Subclass Promises * Pass key through JSON parsing * Wait for preloadModules before resolving module chunks * Initialize lazy resolved values before reading the result * Block a model from initializing if its direct dependencies are pending If a module is blocked, then we can't complete initializing a model. However, we can still let it parse, and then fill in the missing pieces later. We need to block it from resolving until all dependencies have filled in which we can do with a ref count. * Treat blocked modules or models as a special status We currently loop over all chunks at the end to error them if they're still pending. We shouldn't do this if they're pending because they're blocked on an external resource like a module because the module might not resolve before the Flight connection closes and that's not an error. In an alternative solution I had a set that tracked pending chunks and removed one at a time. While the loop at the end is faster it's more work as we go. I figured the extra status might also help debugging. For modules we can probably assume no forward references, and the first async module we can just use the promise as the chunk. So we could probably get away with this only on models that are blocked by modules.
84 lines
2.2 KiB
JavaScript
84 lines
2.2 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import type {JSONValue, ResponseBase} from 'react-client/src/ReactFlightClient';
|
|
|
|
import type {JSResourceReference} from 'JSResourceReference';
|
|
|
|
import type {ModuleMetaData} from 'ReactFlightNativeRelayClientIntegration';
|
|
|
|
export type ModuleReference<T> = JSResourceReference<T>;
|
|
|
|
import {
|
|
parseModelString,
|
|
parseModelTuple,
|
|
} from 'react-client/src/ReactFlightClient';
|
|
|
|
export {
|
|
preloadModule,
|
|
requireModule,
|
|
} from 'ReactFlightNativeRelayClientIntegration';
|
|
|
|
import {resolveModuleReference as resolveModuleReferenceImpl} from 'ReactFlightNativeRelayClientIntegration';
|
|
|
|
import isArray from 'shared/isArray';
|
|
|
|
export type {ModuleMetaData} from 'ReactFlightNativeRelayClientIntegration';
|
|
|
|
export type BundlerConfig = null;
|
|
|
|
export type UninitializedModel = JSONValue;
|
|
|
|
export type Response = ResponseBase;
|
|
|
|
export function resolveModuleReference<T>(
|
|
bundlerConfig: BundlerConfig,
|
|
moduleData: ModuleMetaData,
|
|
): ModuleReference<T> {
|
|
return resolveModuleReferenceImpl(moduleData);
|
|
}
|
|
|
|
function parseModelRecursively(response: Response, parentObj, key, value) {
|
|
if (typeof value === 'string') {
|
|
return parseModelString(response, parentObj, key, value);
|
|
}
|
|
if (typeof value === 'object' && value !== null) {
|
|
if (isArray(value)) {
|
|
const parsedValue = [];
|
|
for (let i = 0; i < value.length; i++) {
|
|
(parsedValue: any)[i] = parseModelRecursively(
|
|
response,
|
|
value,
|
|
'' + i,
|
|
value[i],
|
|
);
|
|
}
|
|
return parseModelTuple(response, parsedValue);
|
|
} else {
|
|
const parsedValue = {};
|
|
for (const innerKey in value) {
|
|
(parsedValue: any)[innerKey] = parseModelRecursively(
|
|
response,
|
|
value,
|
|
innerKey,
|
|
value[innerKey],
|
|
);
|
|
}
|
|
return parsedValue;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
const dummy = {};
|
|
|
|
export function parseModel<T>(response: Response, json: UninitializedModel): T {
|
|
return (parseModelRecursively(response, dummy, '', json): any);
|
|
}
|