For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-import-sync.md.
  • 简体中文
  • Sync Imports S2

    中文标题:同步导入

    提案概览
    提案速览

    该提案引入了 import.sync,一个用于 ES 模块的同步导入函数,使得在模块已经可用时能够同步动态加载说明符。它基于 Defer Import Eval 提案中的同步求值语义,并在模块不可同步获得或使用顶层 await 时抛出错误。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    同步导入

    状态

    提案发起人:Guy Bedford 阶段:2

    问题陈述

    当模块已经完全加载到模块注册表中时,支持一个同步导入函数将会很有用,以便在同步函数路径中加载动态说明符表达式。

    背景

    随着我们进入原生 ESM 在 JS 生态系统中被广泛采用的成熟阶段,诸如 Node.js 中的 require(esm) 等特性为许多人解锁了升级路径,但在从 CommonJS 迁移到 ES 模块的道路上仍存在一些遗留的可用性问题。

    特别是,Node.js 中的 CommonJS 用户习惯于能够同步动态地 require 模块,而不必因此将他们的代码路径转换为异步。

    延迟导入求值 通过允许模块的同步懒加载解决了其中一个问题。它通过有效地将模块加载流程中的异步方面与同步方面分离,从而允许在延迟命名空间上使用同步求值函数

    即使支持了这个提案,当说明符预先未知时,动态懒加载仍然存在空白,因为动态的 import.defer(specifier) 仍然是一个异步函数。

    使用与 Defer Import Eval 提案中已经定义的同步求值完全相同的语义,我们可以为 JavaScript 提供一个显式的同步导入钩子,从而为 JavaScript 开发者解决这个可用性问题。

    以前,在 ESM 规范的早期阶段,启用此类功能的主要障碍之一是异步解析问题。后来事实证明,所有 JS 环境都实现了同步模块解析。 因此,鉴于这一约束,同步导入是可能的。

    提案

    我们提议为 ES 模块公开一个显式的同步导入函数,作为 Defer Import Eval 提案中已定义的同步执行行为的直接扩展:

    // 如果模块可以同步获得,则同步导入该模块
    const ns = import.sync('./mod.js');

    该提案的主要设计是,当模块不可同步获得或使用了顶层 await 时,抛出一个新的 Error

    模块是否可同步获得将是一个由宿主决定的属性。

    使用场景

    获取已加载的模块

    在 Web 上,如果一个模块之前已经被加载过,那么它总是可以同步获得的。

    这样,import.sync() 可以像注册表获取器一样工作:

    import 'app';
    
    // 如果 'app' 之前已被加载,这总是有效的
    const app = import.sync('app');

    条件加载

    与动态导入一样,使用同步导入,可以检查模块或内置模块是否可用,但是同步地进行。

    例如,检查宿主内置模块是否可用:

    let fs;
    try {
      fs = import.sync('node:fs');
    } catch {}
    
    if (fs) {
      // 仅在可用时使用 node:fs
    }

    或者一个条件绑定到框架依赖的库:

    let react;
    try {
      react = import.sync('react');
    } catch {}
    
    if (react) {
      // 如果可用,则绑定到 React 框架
    }

    同步加载模块表达式和模块声明

    支持导入没有 TLA 和异步依赖的模块表达式:

    // 立即输出 'hello world'
    import.sync(module {
      console.log('hello world');
    })

    同样适用于模块声明:

    module dep {
      console.log('hi');
    }
    
    module x {
      import dep;
    }
    
    // 输出 'hi',因为两个模块都可以同步获得
    const instance = import.sync(x);

    常见问题

    导入同步是模块加载阶段吗?

    不,与 defersource 不同,import.sync 不是一个阶段,它是一个新的元属性,类似于 import.meta

    不支持类似于 import sync mod from 'mod' 的语法。

    要预先保证图是同步的,请参见 模块同步断言 提案,该提案可能会提供导入属性或其他方式。

    提出问题请提交 issue