React DOM flight server host dispatcher
一、作用
二、预加载
备注
resolveRequest由 ReactFlightServer#resolveRequest 提供getHints由 ReactFlightServer#getHints 提供emitHint由 ReactFlightServer#emitHint 提供
export function preload(
href: string,
as: string,
options?: ?PreloadImplOptions,
) {
if (typeof href === 'string') {
const request = resolveRequest();
if (request) {
const hints = getHints(request);
let key = 'L';
if (as === 'image' && options) {
key += getImagePreloadKey(
href,
options.imageSrcSet,
options.imageSizes,
);
} else {
key += `[${as}]${href}`;
}
if (hints.has(key)) {
// duplicate hint
// 重复提示
return;
}
hints.add(key);
const trimmed = trimOptions(options);
if (trimmed) {
emitHint(request, 'L', [href, as, trimmed]);
} else {
emitHint(request, 'L', [href, as]);
}
} else {
previousDispatcher.L(/* preload */ href, as, options);
}
}
}
三、预加载模块
备注
resolveRequest由 ReactFlightServer#resolveRequest 提供getHints由 ReactFlightServer#getHints 提供emitHint由 ReactFlightServer#emitHint 提供
export function preloadModule(
href: string,
options?: ?PreloadModuleImplOptions,
): void {
if (typeof href === 'string') {
const request = resolveRequest();
if (request) {
const hints = getHints(request);
const key = 'm|' + href;
if (hints.has(key)) {
// duplicate hint
// 重复提示
return;
}
hints.add(key);
const trimmed = trimOptions(options);
if (trimmed) {
return emitHint(request, 'm', [href, trimmed]);
} else {
return emitHint(request, 'm', href);
}
} else {
previousDispatcher.m(/* preloadModule */ href, options);
}
}
}
四、常量
1. 上一个调度器
备注
源码中 27 - 39 行
ReactDOMSharedInternals由 ReactDOMSharedInternals 提供
const previousDispatcher =
ReactDOMSharedInternals.d; /* ReactDOMCurrentDispatcher */
ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */ = {
f /* flushSyncWork */: previousDispatcher.f /* flushSyncWork */,
r /* requestFormReset */: previousDispatcher.r /* requestFormReset */,
D /* prefetchDNS */: prefetchDNS,
C /* preconnect */: preconnect,
L /* preload */: preload,
m /* preloadModule */: preloadModule,
X /* preinitScript */: preinitScript,
S /* preinitStyle */: preinitStyle,
M /* preinitModuleScript */: preinitModuleScript,
};
五、工具
1. 预取 DNS
备注
resolveRequest由 ReactFlightServer#resolveRequest 提供getHints由 ReactFlightServer#getHints 提供emitHint由 ReactFlightServer#emitHint 提供
function prefetchDNS(href: string) {
if (typeof href === 'string' && href) {
const request = resolveRequest();
if (request) {
const hints = getHints(request);
const key = 'D|' + href;
if (hints.has(key)) {
// duplicate hint
// 重复提示
return;
}
hints.add(key);
emitHint(request, 'D', href);
} else {
previousDispatcher.D(/* prefetchDNS */ href);
}
}
}
2. 预连接
备注
resolveRequest由 ReactFlightServer#resolveRequest 提供getHints由 ReactFlightServer#getHints 提供emitHint由 ReactFlightServer#emitHint 提供
function preconnect(href: string, crossOrigin?: ?CrossOriginEnum) {
if (typeof href === 'string') {
const request = resolveRequest();
if (request) {
const hints = getHints(request);
const key = `C|${crossOrigin == null ? 'null' : crossOrigin}|${href}`;
if (hints.has(key)) {
// duplicate hint
// 重复提示
return;
}
hints.add(key);
if (typeof crossOrigin === 'string') {
emitHint(request, 'C', [href, crossOrigin]);
} else {
emitHint(request, 'C', href);
}
} else {
previousDispatcher.C(/* preconnect */ href, crossOrigin);
}
}
}
3. 预初始化样式
备注
resolveRequest由 ReactFlightServer#resolveRequest 提供getHints由 ReactFlightServer#getHints 提供emitHint由 ReactFlightServer#emitHint 提供
function preinitStyle(
href: string,
precedence: ?string,
options?: ?PreinitStyleOptions,
) {
if (typeof href === 'string') {
const request = resolveRequest();
if (request) {
const hints = getHints(request);
const key = 'S|' + href;
if (hints.has(key)) {
// duplicate hint
// 重复提示
return;
}
hints.add(key);
const trimmed = trimOptions(options);
if (trimmed) {
return emitHint(request, 'S', [
href,
typeof precedence === 'string' ? precedence : 0,
trimmed,
]);
} else if (typeof precedence === 'string') {
return emitHint(request, 'S', [href, precedence]);
} else {
return emitHint(request, 'S', href);
}
} else {
previousDispatcher.S(/* preinitStyle */ href, precedence, options);
}
}
}
4. 预初始化脚本
备注
resolveRequest由 ReactFlightServer#resolveRequest 提供getHints由 ReactFlightServer#getHints 提供emitHint由 ReactFlightServer#emitHint 提供
function preinitScript(src: string, options?: ?PreinitScriptOptions) {
if (typeof src === 'string') {
const request = resolveRequest();
if (request) {
const hints = getHints(request);
const key = 'X|' + src;
if (hints.has(key)) {
// duplicate hint
// 重复提示
return;
}
hints.add(key);
const trimmed = trimOptions(options);
if (trimmed) {
return emitHint(request, 'X', [src, trimmed]);
} else {
return emitHint(request, 'X', src);
}
} else {
previousDispatcher.X(/* preinitScript */ src, options);
}
}
}
5. 预初始化模块脚本
备注
resolveRequest由 ReactFlightServer#resolveRequest 提供getHints由 ReactFlightServer#getHints 提供emitHint由 ReactFlightServer#emitHint 提供
function preinitModuleScript(
src: string,
options?: ?PreinitModuleScriptOptions,
) {
if (typeof src === 'string') {
const request = resolveRequest();
if (request) {
const hints = getHints(request);
const key = 'M|' + src;
if (hints.has(key)) {
// duplicate hint
// 重复提示
return;
}
hints.add(key);
const trimmed = trimOptions(options);
if (trimmed) {
return emitHint(request, 'M', [src, trimmed]);
} else {
return emitHint(request, 'M', src);
}
} else {
previousDispatcher.M(/* preinitModuleScript */ src, options);
}
}
}
6. 修剪选项
// Flight normally encodes undefined as a special character however for directive option
// arguments we don't want to send unnecessary keys and bloat the payload so we create a
// trimmed object which omits any keys with null or undefined values.
// This is only typesafe because these option objects have entirely optional fields where
// null and undefined represent the same thing as no property.
// Flight 通常会将 `undefined` 编码为特殊字符,但对于指令选项参数,我们不想发送不必要的键并增加负
// 载,因此我们创建了一个精简对象,省略任何值为 `null` 或 `undefined` 的键。这只有在类型安全的情
// 况下才可行,因为这些选项对象的字段都是可选的,`null` 和 `undefined` 与没有属性表示相同的意思
function trimOptions<
T extends
| PreloadImplOptions
| PreloadModuleImplOptions
| PreinitStyleOptions
| PreinitScriptOptions
| PreinitModuleScriptOptions,
>(options: ?T): ?T {
if (options == null) return null;
let hasProperties = false;
const trimmed: T = {} as any;
for (const key in options) {
if (options[key] != null) {
hasProperties = true;
(trimmed as any)[key] = options[key];
}
}
return hasProperties ? trimmed : null;
}
7. 获取图片预加载键
function getImagePreloadKey(
href: string,
imageSrcSet: ?string,
imageSizes: ?string,
) {
let uniquePart = '';
if (typeof imageSrcSet === 'string' && imageSrcSet !== '') {
uniquePart += '[' + imageSrcSet + ']';
if (typeof imageSizes === 'string') {
uniquePart += '[' + imageSizes + ']';
}
} else {
uniquePart += '[][]' + href;
}
return `[image]${uniquePart}`;
}