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-jobcallback-module.md.
  • 简体中文
  • Propagate active ScriptOrModule with JobCallback Record S2

    中文标题:使用 JobCallback 记录传播活动 ScriptOrModule

    提案概览
    提案速览

    该提案旨在统一活动 ScriptOrModule 的传播,使其在调用 promise.then 时确定,而不是在 HostEnqueuePromiseJob 时确定,从而避免暴露内部 [[PromiseState]]。它要求通过 promise 作业和 FinalizationRegistry 回调传播,与 HTML 现有的 HostMakeJobCallback 行为保持一致。

    Note

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

    ecma262#3195

    这是 https://github.com/tc39/ecma262/pull/3195 的规范性更改的仓库。

    状态:Stage 2

    提案发起人:Chengzhong Wu (@legendecas)

    动机

    目标是避免通过宿主钩子要求向 Promise 处理器暴露内部插槽 [[PromiseState]],而是使用 promise.then(onFulfill, onRejection)

    ECMA262 HostEnqueuePromiseJob 定义宿主必须将其实现为:

    HostEnqueuePromiseJob 的时机取决于内部 Promise 的 [[PromiseState]]。而本动机期望 ActiveScriptOrModule 在调用 promise.then() 时被确定。

    // 模块 A
    const {promise, resolve} = Promise.withResolvers();
    promise.then(handler); // (1)
    
    // 模块 B
    resolve(); // 为 (1) 调用 HostEnqueuePromiseJob
    promise.then(handler); // (2) 调用 HostEnqueuePromiseJob

    即在上面的例子中,调用点 (1) 处的 handler 的 ActiveScriptOrModule 应为“模块 A”,而调用点 (2) 处应为“模块 B”。

    HTML 集成

    HTML HostEnqueuePromiseJob 并不遵循 ecma262 的要求。

    然而,HTML 规范定义活动的 ScriptOrModule 在调用 HostMakeJobCallback 时被保存,而不是在调用 HostEnqueuePromiseJob 时。这两个宿主钩子被连续地调用,且具有相同的活动脚本或模块。

    这一更改也强制要求活动脚本通过 promise 作业和 FinalizationRegistry 清理回调进行传播。

    例如,下面的示例使用了依赖于原始脚本的现任文档 URL 的 HTML API。

    const frame = frames[0];
    const setLocationHref = Object
      .getOwnPropertyDescriptor(frame.location, "href")
      .set
      .bind(frame.location);
    
    framePromise.resolve("./page-1").then(setLocationHref);

    这种提议的行为在 HTML 规范中已经存在,因为 HTML 的 HostMakeJobCallback 已经传播了活动脚本。

    提议的更改

    查看 https://github.com/tc39/ecma262/pull/3195

    实际实现状态的现实是:

    .resolved.then(f)resolve.then(v => f(v))pending.then(f)pending.then(v => f(v))
    HTMLouterouterouterouter
    ECMA-262outerouter☹️ inner☹️ inner
    Chrome/Firefox☹️ innerouter☹️ innerouter
    Safariouterouter☹️ inner☹️ inner
    • pending 在内部 iframe 中 resolve。
    • f 是 iframe 的 setLocationHref
    • outer: url 解析到外层页面。
    • inner: url 解析到内部 iframe。

    结论:

    • ECMA-262 和 Safari 暴露了 [[PromiseState]]
    • Chrome/Firefox 不尊重 .then(f) 等同于 .then(v => f(v))
    • HTML 和提议的行为都不具有这些问题。

    提议的更改还修复了 ecma262 HostEnqueuePromiseJob 和 HTML HostMakeJobCallback 之间的不一致要求。