You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript暴露模块模式中实现函数链式调用?

实现链式调用的解决方案

要实现moduleAda.message.send("hello").display.show()这样的链式调用,我们需要解决两个核心问题:

  1. 让message.send()返回的对象包含display模块的引用,这样才能链式调用其方法。
  2. 处理send()内部的异步操作(queryAda是Promise),确保display.show()能拿到异步请求完成后的结果。

下面是具体的重构步骤和代码:

1. 调整模块内部结构,添加状态存储

首先在暴露模块模式的内部添加一个状态变量,用来暂存send()的输入和异步返回的结果,这样display.show()可以直接获取这些数据:

var moduleAda = (function() {
  // 内部状态:存储当前请求的输入和处理后的输出
  var currentRequest = {
    input: null,
    output: null
  };

  // 原有的message和display对象放在这里,后续修改
})();

2. 抽离公共逻辑,避免代码重复

把显示和隐藏消息的逻辑抽成内部函数,让链式调用的方法和独立调用的方法都能复用:

// 内部复用的显示逻辑
function showMessage(input, output) {
  $("#ADA-Q-TXT").text(input);
  $("ADA-BUBBLE").css({ "margin-bottom": "112px" });
  $("ADA-BUBBLE").html(output);
  styleTable();
  setTimeout(function() {
    $("ADA-BUBBLE").addClass("SHOW");
  }, 500);
}

// 内部复用的隐藏逻辑
function hideMessage() {
  $("ADA-BUBBLE").removeClass("SHOW");
  $("ADA-EXAMPLES li").removeClass("SHOW");
  setTimeout(function() {
    $("ADA-EXAMPLES").css({ display: "none" });
  }, 500);
}

3. 重构message.send()方法

修改send()方法,让它返回一个包含display的可链式调用对象,同时封装异步请求逻辑,确保结果能被正确存储:

var message = {
  send: function send(query) {
    // 保存当前请求的输入
    currentRequest.input = query;
    // 显示加载 spinner
    $("spinner").css({ display: "block" });

    // 封装异步请求为Promise(假设queryAda返回jQuery Deferred,本身兼容Promise)
    var requestPromise = queryAda(query)
      .done(function(result) {
        console.log("success", result);
        var processedMessage = cleanAda(result);
        console.log(processedMessage);
        storage.save();
        // 保存成功后的处理结果
        currentRequest.output = processedMessage;
      })
      .fail(function(xhr) {
        console.log("error", xhr);
        var errorMessage = "I'm sorry, but there was an error and I couldn't retrieve your request. Please try again.";
        // 保存错误提示信息
        currentRequest.output = errorMessage;
      })
      .always(function() {
        // 请求完成后隐藏 spinner
        $("spinner").css({ display: "none" });
      });

    // 创建可链式调用的对象:融合Promise和display方法
    var chainableObj = Object.assign({}, requestPromise, {
      display: {
        // 重写show方法,确保等待异步请求完成后执行
        show: function() {
          requestPromise.then(function() {
            showMessage(currentRequest.input, currentRequest.output);
          });
          // 返回自身,支持继续链式调用
          return chainableObj;
        },
        // 复用隐藏逻辑,同时支持链式
        remove: function() {
          hideMessage();
          return chainableObj;
        }
      }
    });

    return chainableObj;
  }
};

4. 保留原display模块的独立调用能力

为了不破坏原有的moduleAda.display.show()或moduleAda.display.remove()调用,我们基于抽离的公共逻辑重新定义display对象:

// 原有的display模块,保留独立调用能力
var display = {
  remove: function() {
    hideMessage();
    // 支持独立链式调用,比如moduleAda.display.remove().show(...)
    return this;
  },
  show: function(input, output) {
    showMessage(input, output);
    return this;
  }
};

5. 完整的模块代码

把所有部分整合起来,最终的moduleAda代码如下:

var moduleAda = (function() {
  // 内部状态:存储当前请求的输入和处理后的输出
  var currentRequest = {
    input: null,
    output: null
  };

  // 内部复用的显示逻辑
  function showMessage(input, output) {
    $("#ADA-Q-TXT").text(input);
    $("ADA-BUBBLE").css({ "margin-bottom": "112px" });
    $("ADA-BUBBLE").html(output);
    styleTable();
    setTimeout(function() {
      $("ADA-BUBBLE").addClass("SHOW");
    }, 500);
  }

  // 内部复用的隐藏逻辑
  function hideMessage() {
    $("ADA-BUBBLE").removeClass("SHOW");
    $("ADA-EXAMPLES li").removeClass("SHOW");
    setTimeout(function() {
      $("ADA-EXAMPLES").css({ display: "none" });
    }, 500);
  }

  var message = {
    send: function send(query) {
      currentRequest.input = query;
      $("spinner").css({ display: "block" });

      var requestPromise = queryAda(query)
        .done(function(result) {
          console.log("success", result);
          var processedMessage = cleanAda(result);
          console.log(processedMessage);
          storage.save();
          currentRequest.output = processedMessage;
        })
        .fail(function(xhr) {
          console.log("error", xhr);
          var errorMessage = "I'm sorry, but there was an error and I couldn't retrieve your request. Please try again.";
          currentRequest.output = errorMessage;
        })
        .always(function() {
          $("spinner").css({ display: "none" });
        });

      var chainableObj = Object.assign({}, requestPromise, {
        display: {
          show: function() {
            requestPromise.then(function() {
              showMessage(currentRequest.input, currentRequest.output);
            });
            return chainableObj;
          },
          remove: function() {
            hideMessage();
            return chainableObj;
          }
        }
      });

      return chainableObj;
    }
  };

  var display = {
    remove: function() {
      hideMessage();
      return this;
    },
    show: function(input, output) {
      showMessage(input, output);
      return this;
    }
  };

  return {
    message: message,
    display: display
  };
})();

6. 链式调用的使用方式

现在你可以按照期望的方式进行链式调用了:

// 基础链式调用
moduleAda.message.send("hello").display.show();

// 连续链式调用(比如发送请求后显示,再隐藏)
moduleAda.message.send("hello").display.show().display.remove();

同时,原有的独立调用方式依然有效:

// 独立显示消息
moduleAda.display.show("custom input", "custom output");

// 独立隐藏消息
moduleAda.display.remove();

关键说明

  • 异步处理:通过将queryAda的请求封装为Promise,在display.show()中使用then()确保只有当异步请求完成后才执行显示逻辑,避免数据未准备好的问题。
  • 链式核心:每个方法返回包含后续可调用方法的对象(这里是chainableObj),这样就能持续链式调用。
  • 代码复用:抽离公共的显示/隐藏逻辑,避免重复代码,同时保证模块的灵活性。

内容的提问来源于stack exchange,提问作者Jon Hart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:42:56