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-function-once.md.
  • 简体中文
  • Function once S1

    中文标题:JavaScript 的 Function.prototype.once

    提案概览
    提案速览

    本提案标准化了 Function.prototype.once 方法,确保函数最多被调用一次,后续调用返回第一次的结果。它解决了 JavaScript 中一次性回调的常见需求。

    Note

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

    用于 JavaScript 的 Function.prototype.once

    ECMAScript Stage-1 提案。2022。

    联合发起人:Hemanth HM;J. S. Choi。

    理由

    确保回调只执行一次(无论回调被调用多少次)通常是很有用的。为此,开发者经常使用“once”函数,这些函数包装回调并确保它们最多被调用一次。本提案将在语言核心中标准化这样一个 once 函数。

    描述

    Function.prototype.once 方法将创建一个新函数,该函数最多调用一次原始函数,无论新函数被调用多少次。此调用中给出的参数会被传递给原始函数。对创建的函数任何后续调用都将返回第一次调用的结果。

    function f (x) { console.log(x); return x * 2; }
    
    const fOnce = f.once();
    fOnce(3); // 打印 3 并返回 6。
    fOnce(3); // 不打印任何内容。返回 6。
    fOnce(2); // 不打印任何内容。返回 6。

    实际示例

    以下代码已被改编以使用本提案。

    来自 execa@6.1.0

    export function execa (file, args, options) {
      /* … */
      const handlePromise = async () => { /* … */ };
      const handlePromiseOnce = handlePromise.once();
      /* … */
      return mergePromise(spawned, handlePromiseOnce);
    });

    来自 glob@7.2.1

    function Glob (pattern, options, cb) {
      /* … */
      if (typeof cb === 'function') {
        cb = cb.once();
        this.on('error', cb);
        this.on('end', function (matches) {
          cb(null, matches);
        })
      } /* … */
    });

    来自 Meteor@2.6.1

    // “我们是否在 git 检出中运行 Meteor?”
    export const inCheckout = (function () {
      try { /* … */ } catch (e) { console.log(e); }
      return false;
    }).once();

    来自 cypress@9.5.2

    cy.on('command:retry', (() => { /* … */ }).once());

    来自 jitsi-meet 1.0.5913

    this._hangup = (() => {
      sendAnalytics(createToolbarEvent('hangup'));
      /* … */
    }).once();

    先例和 Web 兼容性

    有一个流行的 NPM 库,名为 once,它允许猴子补丁,这可能引发对 Function.prototype.once 的 Web 兼容性的担忧。

    然而,自其第一个公开版本以来,once 库的猴子补丁仅是可选启用的。该猴子补丁不是条件性的,并且该库不存在实际的 Web 兼容性风险。

    // 默认形式导出一个函数。
    once = require('once');
    fOnce = once(f);
    
    // 可选形式对 Function.prototype 进行猴子补丁。
    require('once').proto();
    fOnce = f.once();

    来自库的其他流行的 once 函数(例如,lodash.onceUnderscoreonetime)也不使用条件猴子补丁。

    !Function.prototype.once代码搜索(例如 if (!Function.prototype.once) { /* 猴子补丁 */ })在任何索引的开源代码中也没有给出结果。在生产代码中条件性地向 Function.prototype 进行 monkey-patching 一个 once 方法是不太可能的。