mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
a6924d77b1
Originally the idea was to hide all suspending behind getters or proxies. However, this has some issues with perf on hot code like React elements. It also makes it too easy to accidentally access it the first time in an effect or callback where things aren't allowed to suspend. Making it an explicit method call avoids this issue. All other suspending has moved to explicit lazy blocks (and soon elements). The only thing remaining is the root. We could require the root to be an element or block but that creates an unfortunate indirection unnecessarily. Instead, I expose a readRoot method on the response. Typically we try to avoid virtual dispatch but in this case, it's meant that you build abstractions on top of a Flight response so passing it a round is useful.
113 lines
3.1 KiB
JavaScript
113 lines
3.1 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 {Response as ResponseBase, JSONValue} from './ReactFlightClient';
|
|
|
|
import type {StringDecoder} from './ReactFlightClientHostConfig';
|
|
|
|
import {
|
|
createResponse as createResponseImpl,
|
|
resolveModelChunk,
|
|
resolveErrorChunk,
|
|
parseModelFromJSON,
|
|
} from './ReactFlightClient';
|
|
|
|
import {
|
|
supportsBinaryStreams,
|
|
createStringDecoder,
|
|
readPartialStringChunk,
|
|
readFinalStringChunk,
|
|
} from './ReactFlightClientHostConfig';
|
|
|
|
export type Response<T> = ResponseBase<T> & {
|
|
fromJSON: (key: string, value: JSONValue) => any,
|
|
stringDecoder: StringDecoder,
|
|
};
|
|
|
|
export function createResponse<T>(): Response<T> {
|
|
let response: Response<T> = (createResponseImpl(): any);
|
|
response.fromJSON = function(key: string, value: JSONValue) {
|
|
return parseModelFromJSON(response, this, key, value);
|
|
};
|
|
if (supportsBinaryStreams) {
|
|
response.stringDecoder = createStringDecoder();
|
|
}
|
|
return response;
|
|
}
|
|
|
|
function processFullRow<T>(response: Response<T>, row: string): void {
|
|
if (row === '') {
|
|
return;
|
|
}
|
|
let tag = row[0];
|
|
switch (tag) {
|
|
case 'J': {
|
|
let colon = row.indexOf(':', 1);
|
|
let id = parseInt(row.substring(1, colon), 16);
|
|
let json = row.substring(colon + 1);
|
|
let model = JSON.parse(json, response.fromJSON);
|
|
resolveModelChunk(response, id, model);
|
|
return;
|
|
}
|
|
case 'E': {
|
|
let colon = row.indexOf(':', 1);
|
|
let id = parseInt(row.substring(1, colon), 16);
|
|
let json = row.substring(colon + 1);
|
|
let errorInfo = JSON.parse(json);
|
|
resolveErrorChunk(response, id, errorInfo.message, errorInfo.stack);
|
|
return;
|
|
}
|
|
default: {
|
|
// Assume this is the root model.
|
|
let model = JSON.parse(row, response.fromJSON);
|
|
resolveModelChunk(response, 0, model);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
export function processStringChunk<T>(
|
|
response: Response<T>,
|
|
chunk: string,
|
|
offset: number,
|
|
): void {
|
|
let linebreak = chunk.indexOf('\n', offset);
|
|
while (linebreak > -1) {
|
|
let fullrow = response.partialRow + chunk.substring(offset, linebreak);
|
|
processFullRow(response, fullrow);
|
|
response.partialRow = '';
|
|
offset = linebreak + 1;
|
|
linebreak = chunk.indexOf('\n', offset);
|
|
}
|
|
response.partialRow += chunk.substring(offset);
|
|
}
|
|
|
|
export function processBinaryChunk<T>(
|
|
response: Response<T>,
|
|
chunk: Uint8Array,
|
|
): void {
|
|
if (!supportsBinaryStreams) {
|
|
throw new Error("This environment don't support binary chunks.");
|
|
}
|
|
let stringDecoder = response.stringDecoder;
|
|
let linebreak = chunk.indexOf(10); // newline
|
|
while (linebreak > -1) {
|
|
let fullrow =
|
|
response.partialRow +
|
|
readFinalStringChunk(stringDecoder, chunk.subarray(0, linebreak));
|
|
processFullRow(response, fullrow);
|
|
response.partialRow = '';
|
|
chunk = chunk.subarray(linebreak + 1);
|
|
linebreak = chunk.indexOf(10); // newline
|
|
}
|
|
response.partialRow += readPartialStringChunk(stringDecoder, chunk);
|
|
}
|
|
|
|
export {reportGlobalError, close} from './ReactFlightClient';
|