React19源码系列之 API(react-dom)

发布于:2025-05-13 ⋅ 阅读:(12) ⋅ 点赞:(0)

API之 preconnect

preconnect – React 中文文档

preconnect 函数向浏览器提供一个提示,告诉它应该打开到给定服务器的连接。如果浏览器选择这样做,则可以加快从该服务器加载资源的速度。

preconnect(href)

一、使用例子

import { preconnect } from 'react-dom';

function AppRoot() {
  preconnect("https://example.com");
  return ...;
}

import { preconnect } from 'react-dom';

function CallToAction() {
  const onClick = () => {
    preconnect('http://example.com');
    startWizard();
  }
  return (
    <button onClick={onClick}>Start Wizard</button>
  );
}

二、源码

function preconnect(href: string, options?: ?PreconnectOptions) {
  if (typeof href === 'string') {
    const crossOrigin = options
      ? getCrossOriginString(options.crossOrigin)
      : null;
    
    ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
      .C(/* preconnect */ href, crossOrigin);
  }
}

ReactDOMSharedInternals.d.C

preconnect 函数的主要功能是发起一个 preconnect 操作,用于提前建立与指定 href 对应的服务器连接。 

function preconnect(href: string, crossOrigin?: ?CrossOriginEnum) {
  previousDispatcher.C(/* preconnect */ href, crossOrigin);
  preconnectAs('preconnect', href, crossOrigin);
}

API之 prefetchDNS

prefetchDNS – React 中文文档

prefetchDNS 函数向浏览器提供一个提示,告诉它应该查找给定服务器的 IP 地址。如果浏览器选择这样做,则可以加快从该服务器加载资源的速度。

一、使用示范

prefetchDNS 允许提前查找期望从中加载资源的服务器的 IP。

prefetchDNS("https://example.com");

二、源码分析

function prefetchDNS(href: string) {
  if (typeof href === 'string') {
    ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
      .D(/* prefetchDNS */ href);
  }
}

ReactDOMSharedInternals.d.D

prefetchDNS 函数的主要作用是预获取指定 href 对应的 DNS 信息。 

function prefetchDNS(href: string) {
  previousDispatcher.D(/* prefetchDNS */ href);
  preconnectAs('dns-prefetch', href, null);
}

preconnectAs

preconnectAs 函数用于创建 rel="preconnect"rel="dns-prefetch"link 元素,以提前建立与目标服务器的连接或解析 DNS,从而优化后续资源加载的性能。它会检查是否已存在相同配置的预连接标签,避免重复创建。

function preconnectAs(
  rel: 'preconnect' | 'dns-prefetch',
  href: string,
  crossOrigin: ?CrossOriginEnum,
) {
  // 获取document
  const ownerDocument = getGlobalDocument();
  
  if (ownerDocument && typeof href === 'string' && href) {
    const limitedEscapedHref =
      escapeSelectorAttributeValueInsideDoubleQuotes(href);

    // 
    let key = `link[rel="${rel}"][href="${limitedEscapedHref}"]`;
    
    if (typeof crossOrigin === 'string') {
      key += `[crossorigin="${crossOrigin}"]`;
    }
    if (!preconnectsSet.has(key)) {
      preconnectsSet.add(key);

      const preconnectProps = {rel, crossOrigin, href};
      
      if (null === ownerDocument.querySelector(key)) {
        
        const instance = ownerDocument.createElement('link');
        // 设置link元素的属性
        setInitialProperties(instance, 'link', preconnectProps);

        // 标记可提升
        markNodeAsHoistable(instance);

        // 往head元素中添加子元素link标签
        (ownerDocument.head: any).appendChild(instance);
      }
    }
  }
}
类型 作用 使用场景
preconnect 提前建立完成连接。(包括dns解析、tcp握手和 TLS协商) 确定会理解加载跨域资源(如字体、API)
dns-prefetch 仅提前解析dns,不建立TCP、TLS连接。

可能会在未来加载的资源(如广告、第三方内容),减少dns解析延迟。

 API之 preinit

preinit – React 中文文档

preinit 函数向浏览器提供一个提示,告诉它应该开始下载并执行给定的资源,这可以节省时间。preinit 的脚本在下载完成后执行。预初始化的样式表被插入到文档中,这会使它们立即生效。

preinit(href, options) 

参数

  • href:字符串,要下载并执行的资源的 URL。
  • options:对象,可以包含以下属性:
    • as:必需的字符串,表示资源的类型,可能的值包括 scriptstyle
    • precedence:字符串,与样式表一起使用时必需。指定样式表相对于其他样式表的插入位置。具有较高优先级的样式表可以覆盖具有较低优先级的样式表,可能的值包括 resetlowmediumhigh
    • crossOrigin:字符串,表示要使用的 CORS 策略,可能的值为 anonymoususe-credentials
    • integrity:字符串,为资源的加密哈希,用于 验证其真实性
    • nonce:字符串,表示使用严格内容安全策略时允许资源的 加密随机数
    • fetchPriority:字符串,表示建议获取资源的相对优先级,可能的值为 auto(默认值)、highlow

一、使用例子

1、加载script资源

import { preinit } from 'react-dom';

function AppRoot() {
  preinit("https://example.com/script.js", {as: "script"});
  return ...;
}

2、加载style样式资源 

import { preinit } from 'react-dom';

function AppRoot() {
  preinit("https://example.com/style.css", {as: "style", precedence: "medium"});
  return ...;
}

3、在事件程序中使用加载资源 

import { preinit } from 'react-dom';

function CallToAction() {
  const onClick = () => {
    preinit("https://example.com/wizardStyles.css", {as: "style"});
    startWizard();
  }
  return (
    <button onClick={onClick}>Start Wizard</button>
  );
}

二、源码

function preinit(href: string, options: PreinitOptions) {

  if (typeof href === 'string' && options && typeof options.as === 'string') {
    // 获取要下载的资源类型
    const as = options.as;

    // 获取crossorigin属性的值,可能为use-credentials、空字符串或undefined
    const crossOrigin = getCrossOriginStringAs(as, options.crossOrigin);

    // 资源加密哈希
    const integrity =
      typeof options.integrity === 'string' ? options.integrity : undefined;

    // 资源优先级
    const fetchPriority =
      typeof options.fetchPriority === 'string'
        ? options.fetchPriority
        : undefined;

    // 资源为样式表
    if (as === 'style') {
      ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
        .S(
          /* preinitStyle */
          href,// 资源链接
          typeof options.precedence === 'string'
            ? options.precedence
            : undefined,// 资源优先级
          {
            crossOrigin,//
            integrity,//
            fetchPriority,//
          },
        );

      
      // 资源为script脚本
    } else if (as === 'script') {
      ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
        .X(/* preinitScript */ href, {
          crossOrigin,
          integrity,
          fetchPriority,
          nonce: typeof options.nonce === 'string' ? options.nonce : undefined,//安全策略随机数
        });
    }
  }
}

ReactDOMSharedInternals.d.S(preinitStyle)

preinitStyle 函数的主要功能是预处理样式资源。它会检查指定的样式资源(通过 href 标识)是否已存在于全局文档的样式资源中。如果不存在,会创建一个新的样式资源实例(link 元素),设置其属性,并插入到文档中,同时缓存该资源的相关信息。

function preinitStyle(
  href: string,
  precedence: ?string,
  options?: ?PreinitStyleOptions,
) {
  previousDispatcher.S(/* preinitStyle */ href, precedence, options);

  // 获取document对象
  const ownerDocument = getGlobalDocument();
  if (ownerDocument && href) {
    // 获取样式表信息,map类型
    const styles = getResourcesFromRoot(ownerDocument).hoistableStyles;

    // 将href解析返回 格式为‘href=xxxxx’
    const key = getStyleKey(href);
    precedence = precedence || 'default';

    // Check if this resource already exists
    let resource = styles.get(key);
    if (resource) {
      // We can early return. The resource exists and there is nothing
      // more to do
      return;
    }

    // 初始化资源
    const state = {
      loading: NotLoaded,
      preload: null,
    };

    // Attempt to hydrate instance from DOM
    // 查询选取器
    let instance: null | Instance = ownerDocument.querySelector(
      // `link[rel="stylesheet"][${key}]`
      getStylesheetSelectorFromKey(key),
    );
    if (instance) {
      // 资源已加载并插入
      state.loading = Loaded | Inserted;
    } else {
      // Construct a new instance and insert it
      // 处理link相关属性
      const stylesheetProps = Object.assign(
        ({
          rel: 'stylesheet',
          href,
          'data-precedence': precedence,
        }: StylesheetProps),
        options,
      );
      const preloadProps = preloadPropsMap.get(key);
      
      if (preloadProps) {
        // 设置stylesheetProps对象中的属性,如title,crossOrigin,refferPolicy
        adoptPreloadPropsForStylesheet(stylesheetProps, preloadProps);
      }
      // 创建link标签
      const link = (instance = ownerDocument.createElement('link'));
      //标记
      markNodeAsHoistable(link);
      // 设置属性
      setInitialProperties(link, 'link', stylesheetProps);

      // 为link设置promise
      (link: any)._p = new Promise((resolve, reject) => {
        link.onload = resolve;
        link.onerror = reject;
      });

      // 处理 load 和 error 事件
      link.addEventListener('load', () => {
        state.loading |= Loaded;
      });
      link.addEventListener('error', () => {
        state.loading |= Errored;
      });

      state.loading |= Inserted;
      // 插入文档
      insertStylesheet(instance, precedence, ownerDocument);
    }

    // Construct a Resource and cache it
    resource = {
      type: 'stylesheet',
      instance,
      count: 1,
      state,
    };
    // 缓存资源
    styles.set(key, resource);
    return;
  }
}


const preloadPropsMap: Map<string, PreloadProps | PreloadModuleProps> =
  new Map();

type LoadingState = number;
const NotLoaded = /*       */ 0b000;//0 未加载
const Loaded = /*          */ 0b001;//1 加载
const Errored = /*         */ 0b010;//2 出错
const Settled = /*         */ 0b011;//3
const Inserted = /*        */ 0b100;//4 插入

type StylesheetProps = {
  rel: 'stylesheet',
  href: string,
  'data-precedence': string,
  [string]: mixed,
};

function adoptPreloadPropsForStylesheet(
  stylesheetProps: StylesheetProps,
  preloadProps: PreloadProps | PreloadModuleProps,
): void {
  if (stylesheetProps.crossOrigin == null)
    stylesheetProps.crossOrigin = preloadProps.crossOrigin;
  
  if (stylesheetProps.referrerPolicy == null)
    stylesheetProps.referrerPolicy = preloadProps.referrerPolicy;
  
  if (stylesheetProps.title == null) stylesheetProps.title = preloadProps.title;
}

ReactDOMSharedInternals.d.X(preinitScript)

preinitScript 函数的主要功能是预初始化 JavaScript 脚本资源。它会检查指定 src 的脚本是否已存在于文档中,如果不存在则创建并插入一个新的 script 标签,同时缓存该资源的相关信息。该函数支持从现有 DOM 中复用脚本实例,也能处理预加载属性,并确保脚本以异步方式加载。

function preinitScript(src: string, options?: ?PreinitScriptOptions) {
  previousDispatcher.X(/* preinitScript */ src, options);

  // 获取document对象
  const ownerDocument = getGlobalDocument();
  if (ownerDocument && src) {
    // 获取资源
    const scripts = getResourcesFromRoot(ownerDocument).hoistableScripts;

    // src=xxxx
    const key = getScriptKey(src);

    // Check if this resource already exists
    let resource = scripts.get(key);
    if (resource) {
      // We can early return. The resource exists and there is nothing
      // more to do
      return;
    }

    // Attempt to hydrate instance from DOM
    let instance: null | Instance = ownerDocument.querySelector(
      getScriptSelectorFromKey(key),
    );
    if (!instance) {
      // Construct a new instance and insert it
      const scriptProps = Object.assign(
        ({
          src,
          async: true,// 异步加载
        }: ScriptProps),
        options,
      );
      // Adopt certain preload props
      const preloadProps = preloadPropsMap.get(key);
      if (preloadProps) {
        // 设置属性integrity、referrerPolicy、crossOrigin
        adoptPreloadPropsForScript(scriptProps, preloadProps);
      }
      // 创建script标签
      instance = ownerDocument.createElement('script');
      // 打标记
      markNodeAsHoistable(instance);
      // 设置属性
      setInitialProperties(instance, 'link', scriptProps);
      // 添加
      (ownerDocument.head: any).appendChild(instance);
    }

    // Construct a Resource and cache it
    resource = {
      type: 'script',
      instance,
      count: 1,
      state: null,
    };
    scripts.set(key, resource);
    return;
  }
}

function getScriptSelectorFromKey(key: string): string {
  return 'script[async]' + key;
}

function adoptPreloadPropsForScript(
  scriptProps: ScriptProps,
  preloadProps: PreloadProps | PreloadModuleProps,
): void {
  if (scriptProps.crossOrigin == null)
    scriptProps.crossOrigin = preloadProps.crossOrigin;
  if (scriptProps.referrerPolicy == null)
    scriptProps.referrerPolicy = preloadProps.referrerPolicy;
  if (scriptProps.integrity == null)
    scriptProps.integrity = preloadProps.integrity;
}

API之 preinitModule

preinitModule – React 中文文档

preinitModule 函数向浏览器提供一个提示,告诉它应该开始下载并执行给定的模块,这可以节省时间。预初始化的模块在下载完成后执行。

preinitModule(href, options) 

参数

  • href:字符串,要下载并执行的模块的 URL。
  • options:对象,可以包含以下属性:
    • as:必需的字符串,只能是 script
    • crossOrigin:字符串,表示要使用的 CORS 策略,可能的值为 anonymoususe-credentials
    • integrity:字符串,为资源的加密哈希,用于 验证其真实性
    • nonce:字符串,表示使用严格内容安全策略时允许资源的 加密随机数

一、使用示范

import { preinitModule } from 'react-dom';

function AppRoot() {
  preinitModule("https://example.com/module.js", {as: "script"});
  return ...;
}

import { preinitModule } from 'react-dom';

function CallToAction() {
  const onClick = () => {
    preinitModule("https://example.com/module.js", {as: "script"});
    startWizard();
  }
  return (
    <button onClick={onClick}>Start Wizard</button>
  );
}

二、源码分析

function preinitModule(href: string, options?: ?PreinitModuleOptions) {
  if (typeof href === 'string') {
    if (typeof options === 'object' && options !== null) {
      if (options.as == null || options.as === 'script') {
        const crossOrigin = getCrossOriginStringAs(
          options.as,
          options.crossOrigin,
        );
        ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
          .M(/* preinitModuleScript */ href, {
            crossOrigin,
            integrity:
              typeof options.integrity === 'string'
                ? options.integrity
                : undefined,
            nonce:
              typeof options.nonce === 'string' ? options.nonce : undefined,
          });
      }
    } else if (options == null) {
      ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
        .M(/* preinitModuleScript */ href);
    }
  }
}

ReactDOMSharedInternals.d.M

preinitModuleScript 函数的核心功能是预初始化 ES6 模块脚本资源。它会检查指定 src 的模块脚本是否已存在于文档中,如果不存在则创建并插入一个新的 script 标签(设置为 type="module"),同时缓存该资源的相关信息。

function preinitModuleScript(
  src: string,
  options?: ?PreinitModuleScriptOptions,
) {
  previousDispatcher.M(/* preinitModuleScript */ src, options);

  // 获取document对象
  const ownerDocument = getGlobalDocument();
  if (ownerDocument && src) {
    // 获取资源
    const scripts = getResourcesFromRoot(ownerDocument).hoistableScripts;

    const key = getScriptKey(src);

    // Check if this resource already exists
    let resource = scripts.get(key);
    if (resource) {
      // We can early return. The resource exists and there is nothing
      // more to do
      return;
    }

    // Attempt to hydrate instance from DOM
    let instance: null | Instance = ownerDocument.querySelector(
      getScriptSelectorFromKey(key),
    );
    if (!instance) {
      // Construct a new instance and insert it
      const scriptProps = Object.assign(
        ({
          src,
          async: true,//异步加载
          type: 'module',// 模块
        }: ScriptProps),
        options,
      );
      // Adopt certain preload props
      const preloadProps = preloadPropsMap.get(key);
      if (preloadProps) {
        // 如果存在预加载属性 preloadProps,则将其应用到脚本属性中(如 integrity、referrerPolicy、crossOrigin 等)。
        adoptPreloadPropsForScript(scriptProps, preloadProps);
      }
      instance = ownerDocument.createElement('script');
      // 标记可提升
      markNodeAsHoistable(instance);
      setInitialProperties(instance, 'link', scriptProps);
      (ownerDocument.head: any).appendChild(instance);
    }

    // Construct a Resource and cache it
    resource = {
      type: 'script',
      instance,
      count: 1,
      state: null,
    };
    scripts.set(key, resource);
    return;
  }
}

API之 preload

preload – React 中文文档

preload 函数的主要作用是对资源进行预加载操作。它会先对传入的参数进行有效性检查,确保参数类型符合要求,然后触发资源的预加载。

preload(href, options)

参数

  • href:字符串,要下载的资源的 URL。
  • options:对象,可以包含以下属性:
    • as:必需的字符串,表示资源的类型,可能的值 包括 audio、document、embed、fetch、font、image、object、script、style、track、video 与 worker。
    • crossOrigin:字符串,表示要使用的 CORS 策略,可能的值为 anonymous 与 use-credentials。当 as 设置为 "fetch" 时是必需的。
    • referrerPolicy:字符串,表示在获取时发送的 referer 请求头,可能的值为 no-referrer-when-downgrade(默认值)、no-referrer、origin、origin-when-cross-origin 与 unsafe-url。
    • integrity:字符串,为资源的加密哈希,用于 验证其真实性。
    • type:字符串,表示资源的 MIME 类型。
    • nonce:字符串,表示使用严格内容安全策略时允许资源的 加密随机数。
    • fetchPriority:字符串,为获取资源建议的相对优先级,可能的值为 auto(默认值)、high 与 low。
    • imageSrcSet:字符串,仅与 as: "image" 一起使用,用于指定 图像的源集。
    • imageSizes:字符串,仅与 as: "image" 一起使用,用于指定 图像的尺寸。

 一、使用示范

  1. 渲染时进行预加载
  2. 在事件处理程序中预加载

preload 可以预获取期望使用的资源,比如样式表、字体或外部脚本。

preload("https://example.com/font.woff2", {as: "font"});
    import { preload } from 'react-dom';
    
    function AppRoot() {
      preload("https://example.com/style.css", {as: "style"});
      preload("https://example.com/font.woff2", {as: "font"});
      return ...;
    }

    二、源码

    function preload(href: string, options: PreloadOptions) {
      if (
        typeof href === 'string' &&
        typeof options === 'object' &&
        options !== null &&
        typeof options.as === 'string'
      ) {
        
        // as:从 options 对象中提取 as 属性的值,该属性通常用于指定预加载资源的类型,如 'script'、'style' 等。
        const as = options.as;
    
        // 调用 getCrossOriginStringAs 函数,根据 as 和 options.crossOrigin 生成跨域相关的字符串。
        const crossOrigin = getCrossOriginStringAs(as, options.crossOrigin);
        
        ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
          .L(/* preload */ href, as, {
            crossOrigin,
            integrity:
              typeof options.integrity === 'string' ? options.integrity : undefined,
            nonce: typeof options.nonce === 'string' ? options.nonce : undefined,
            type: typeof options.type === 'string' ? options.type : undefined,
            fetchPriority:
              typeof options.fetchPriority === 'string'
                ? options.fetchPriority
                : undefined,
            referrerPolicy:
              typeof options.referrerPolicy === 'string'
                ? options.referrerPolicy
                : undefined,
            imageSrcSet:
              typeof options.imageSrcSet === 'string'
                ? options.imageSrcSet
                : undefined,
            imageSizes:
              typeof options.imageSizes === 'string'
                ? options.imageSizes
                : undefined,
            media: typeof options.media === 'string' ? options.media : undefined,
          });
      }
    }
    

    ReactDOMSharedInternals.d.L

    preload 函数主要用于预加载资源,通过创建 rel="preload"link 元素来实现。它会根据资源的类型(as)和相关选项(options)生成合适的选择器和属性,检查资源是否已存在于文档中,若不存在则插入新的 link 元素进行预加载,同时处理 Safari 中关于图片 imageSrcSet 的特殊情况。

    function preload(href: string, as: string, options?: ?PreloadImplOptions) {
      previousDispatcher.L(/* preload */ href, as, options);
    
      // 获取document对象
      const ownerDocument = getGlobalDocument();
      if (ownerDocument && href && as) {
        // 预加载选择器
        let preloadSelector = `link[rel="preload"][as="${escapeSelectorAttributeValueInsideDoubleQuotes(
          as,
        )}"]`;
    
        // 当资源类型为image时,处理
        if (as === 'image') {
          if (options && options.imageSrcSet) {
            preloadSelector += `[imagesrcset="${escapeSelectorAttributeValueInsideDoubleQuotes(
              options.imageSrcSet,
            )}"]`;
            if (typeof options.imageSizes === 'string') {
              preloadSelector += `[imagesizes="${escapeSelectorAttributeValueInsideDoubleQuotes(
                options.imageSizes,
              )}"]`;
            }
          } else {
            preloadSelector += `[href="${escapeSelectorAttributeValueInsideDoubleQuotes(
              href,
            )}"]`;
          }
        } else {
          // 对于非图片类型的资源,直接向选择器中添加 href 属性值。
          preloadSelector += `[href="${escapeSelectorAttributeValueInsideDoubleQuotes(
            href,
          )}"]`;
        }
    
        let key = preloadSelector;
        
        switch (as) {
          case 'style':
            // 当资源类型为 style 时,将 key 更新为 getStyleKey(href) 的返回值
            key = getStyleKey(href);
            break;
          case 'script':
            // 当资源类型为 script 时,将 key 更新为 getScriptKey(href) 的返回值
            key = getScriptKey(href);
            break;
        }
        if (!preloadPropsMap.has(key)) {
    
          // 创建预加载属性
          const preloadProps = Object.assign(
            ({
              rel: 'preload',
              href:
                as === 'image' && options && options.imageSrcSet ? undefined : href,
              as,
            }: PreloadProps),
            options,
          );
          
          preloadPropsMap.set(key, preloadProps);
    
          if (null === ownerDocument.querySelector(preloadSelector)) {
            if (
              as === 'style' &&
              ownerDocument.querySelector(getStylesheetSelectorFromKey(key))
            ) {
              // 若资源类型为 style 且已存在对应样式表(通过 getStylesheetSelectorFromKey(key) 检查),则返回,不进行预加载。
              // We already have a stylesheet for this key. We don't need to preload it.
              return;
            } else if (
              as === 'script' &&
              ownerDocument.querySelector(getScriptSelectorFromKey(key))
            ) {
              // 若资源类型为 script 且已存在对应脚本(通过 getScriptSelectorFromKey(key) 检查),则返回,不进行预加载。
              // We already have a stylesheet for this key. We don't need to preload it.
              return;
            }
            // 创建link元素
            const instance = ownerDocument.createElement('link');
            // 设置初始属性
            setInitialProperties(instance, 'link', preloadProps);
            // 标记可提升
            markNodeAsHoistable(instance);
            // 往head标签中插入子节点
            (ownerDocument.head: any).appendChild(instance);
          }
        }
      }
    }

    API之 preloadModule

    preloadModule – React 中文文档

    preloadModule 可以急切地预获取期望使用的 ESM 模块。

    preloadModule("https://example.com/module.js", {as: "script"});

    参考语法

    preloadModule(href, options)

    参数

    • href:字符串,要下载的资源的 URL。
    • options:对象,可以包含以下属性:
      • as:必需的字符串,表示资源的类型,可能的值 包括 audio、document、embed、fetch、font、image、object、script、style、track、video 与 worker。
      • crossOrigin:字符串,表示要使用的 CORS 策略,可能的值为 anonymous 与 use-credentials。当 as 设置为 "fetch" 时是必需的。
      • integrity:字符串,为资源的加密哈希,用于 验证其真实性。
      • nonce:字符串,表示使用严格内容安全策略时允许资源的 加密随机数。

    一、使用示范

    import { preloadModule } from 'react-dom';
    
    function CallToAction() {
      const onClick = () => {
        preloadModule("https://example.com/module.js", {as: "script"});
        startWizard();
      }
      return (
        <button onClick={onClick}>Start Wizard</button>
      );
    }

    二、源码

    function preloadModule(href: string, options?: ?PreloadModuleOptions) {
      if (typeof href === 'string') {
        if (options) {
          const crossOrigin = getCrossOriginStringAs(
            options.as,
            options.crossOrigin,
          );
          
          ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
            .m(/* preloadModule */ href, {
              as:
                typeof options.as === 'string' && options.as !== 'script'
                  ? options.as
                  : undefined,
              crossOrigin,
              integrity:
                typeof options.integrity === 'string'
                  ? options.integrity
                  : undefined,
            });
          
        } else {
          ReactDOMSharedInternals.d /* ReactDOMCurrentDispatcher */
            .m(/* preloadModule */ href);
        }
      }
     
    }
    

    ReactDOMSharedInternals.d.m

    preloadModule 函数用于预加载 ES6 模块资源,通过创建 rel="modulepreload"link 元素来实现。它会根据资源类型(as)和相关选项生成合适的选择器和属性,检查资源是否已存在于文档中,若不存在则插入新的 link 元素进行预加载。

    function preloadModule(href: string, options?: ?PreloadModuleImplOptions) {
      previousDispatcher.m(/* preloadModule */ href, options);
    
      // 获取document对象
      const ownerDocument = getGlobalDocument();
      
      if (ownerDocument && href) {
        
        const as =
          options && typeof options.as === 'string' ? options.as : 'script';
        
        // 生成预加载选择器 preloadSelector,包含 rel="modulepreload"、资源类型 as 和资源链接 href。
        const preloadSelector = `link[rel="modulepreload"][as="${escapeSelectorAttributeValueInsideDoubleQuotes(
          as,
        )}"][href="${escapeSelectorAttributeValueInsideDoubleQuotes(href)}"]`;
    
        let key = preloadSelector;
        switch (as) {
          case 'audioworklet':
          case 'paintworklet':
          case 'serviceworker':
          case 'sharedworker':
          case 'worker':
          case 'script': {
            key = getScriptKey(href);
            break;
          }
        }
    
        if (!preloadPropsMap.has(key)) {
          
          const props: PreloadModuleProps = Object.assign(
            ({
              rel: 'modulepreload',
              href,
            }: PreloadModuleProps),
            options,
          );
          preloadPropsMap.set(key, props);
    
          if (null === ownerDocument.querySelector(preloadSelector)) {
            switch (as) {
              case 'audioworklet':
              case 'paintworklet':
              case 'serviceworker':
              case 'sharedworker':
              case 'worker':
              case 'script': {
                if (ownerDocument.querySelector(getScriptSelectorFromKey(key))) {
                  return;
                }
              }
            }
            const instance = ownerDocument.createElement('link');
            setInitialProperties(instance, 'link', props);
            markNodeAsHoistable(instance);
            (ownerDocument.head: any).appendChild(instance);
          }
        }
      }
    }

    工具函数之 getCrossOriginStringAs

    返回值只有三种情况:use-credentials、空字符串、undefined。

    function getCrossOriginStringAs(
      as: ?string,// 资源类型
      input: ?string,// crossorigin属性值
    ): ?CrossOriginString {
      // 字体类型返回空字符串
      if (as === 'font') {
        return '';
      }
      if (typeof input === 'string') {
        // 如果crossorigin值为use-credentials,否则返回空字符串
        return input === 'use-credentials' ? input : '';
      }
      
      return undefined;
    }

    工具函数之 getCrossOriginString

    返回值只有三种情况:use-credentials、空字符串、undefined。

    function getCrossOriginString(input: ?string): ?CrossOriginString {
      if (typeof input === 'string') {
        return input === 'use-credentials' ? input : '';
      }
      return undefined;
    }

    工具函数之 getGlobalDocument

    获取document对象。

    const globalDocument = typeof document === 'undefined' ? null : document;
    
    function getGlobalDocument(): ?Document {
      return globalDocument;
    }

    工具函数之 getResourcesFromRoot 

    获取资源,当资源不存在时进行初始化操作后返回。

    function getResourcesFromRoot(root: HoistableRoot): RootResources {
      // 获取资源
      let resources = (root: any)[internalRootNodeResourcesKey];
      if (!resources) {
        // 设置资源
        resources = (root: any)[internalRootNodeResourcesKey] = {
          hoistableStyles: new Map(),
          hoistableScripts: new Map(),
        };
      }
      return resources;
    }
    
    const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
    export type HoistableRoot = Document | ShadowRoot;
    export type HoistableRoot = Document | ShadowRoot;
    export type RootResources = {
      hoistableStyles: Map<string, StyleResource>,
      hoistableScripts: Map<string, ScriptResource>,
    };

    工具函数之 markNodeAsHoistable 

    设置节点为可提升。

    function markNodeAsHoistable(node: Node) {
      (node: any)[internalHoistableMarker] = true;
    }
    
    const internalHoistableMarker = '__reactMarker$' + randomKey;

    工具函数之 getStyleKey

    function getStyleKey(href: string) {
      const limitedEscapedHref =
        escapeSelectorAttributeValueInsideDoubleQuotes(href);
      return `href="${limitedEscapedHref}"`;
    }

    工具函数之 getScriptKey

    function getScriptKey(src: string): string {
      const limitedEscapedSrc = escapeSelectorAttributeValueInsideDoubleQuotes(src);
      return `[src="${limitedEscapedSrc}"]`;
    }

    工具函数之 escapeSelectorAttributeValueInsideDoubleQuotes

    // 正则表达式用于匹配字符串中的换行符(\n)、双引号(")和反斜杠(\\)。g 标志表示全局匹配
    const escapeSelectorAttributeValueInsideDoubleQuotesRegex = /[\n\"\\]/g;
    
    function escapeSelectorAttributeValueInsideDoubleQuotes(
      value,
    ) {
      return value.replace(
        escapeSelectorAttributeValueInsideDoubleQuotesRegex,
        ch => '\\' + ch.charCodeAt(0).toString(16) + ' ',
      );
    }

    const input = 'This is a string with "quotes" and \n newlines and \\ backslashes.';
    const escaped = escapeSelectorAttributeValueInsideDoubleQuotes(input);
    console.log(escaped);
    // This is a string with \22 quotes\22  and \a  newlines and \5c  backslashes.

    工具函数之 getStylesheetSelectorFromKey 

    function getStylesheetSelectorFromKey(key: string) {
      return `link[rel="stylesheet"][${key}]`;
    }
    

    工具函数之 insertStylesheet

    insertStylesheet 函数的主要作用是将样式元素(linkstyle)按照特定的优先级规则插入到文档中。它会根据元素的 data-precedence 属性值来确定插入位置,确保相同优先级的样式元素相邻排列,并且按照优先级从高到低的顺序排列在文档中。

    function insertStylesheet(
      instance: Element,
      precedence: string,// 优先级
      root: HoistableRoot,
    ): void {
    
      // 使用 querySelectorAll 查找根节点 root 下所有带有 data-precedence 属性的样式元素(包括 link 和 style)。
      const nodes = root.querySelectorAll(
        'link[rel="stylesheet"][data-precedence],style[data-precedence]',
      );
      // 最后一个
      const last = nodes.length ? nodes[nodes.length - 1] : null;
      
      let prior = last;
      
      for (let i = 0; i < nodes.length; i++) {
        const node = nodes[i];
        // 获取优先级
        const nodePrecedence = node.dataset.precedence;
        // 如果当前元素的 data-precedence 与目标优先级 precedence 相同,则更新 prior 为该元素。
        if (nodePrecedence === precedence) {
          prior = node;
        } else if (prior !== last) {
          // 退出循环
          break;
        }
      }
    
      if (prior) {
        // 新元素插入到 prior 的下一个兄弟节点之前
        ((prior.parentNode: any): Node).insertBefore(instance, prior.nextSibling);
      } else {
        const parent =
          root.nodeType === DOCUMENT_NODE
          // 将元素插入到文档的 head 中作为第一个子元素
            ? ((((root: any): Document).head: any): Element)
          // 插入到 Shadow DOM 的根节点中作为第一个子元素
            : ((root: any): ShadowRoot);
        parent.insertBefore(instance, parent.firstChild);
      }
    }