重新登录后,拉起收银台失败问题

36 阅读4分钟

H5Pay 实例创建时机对比分析

一、两种创建方式

方式一:模块加载时创建(之前的方式)

// 在模块顶层,模块加载时立即创建
const h5Pay = new H5Pay({
  env: getAppEnv(),
  ubt: UBTHelper.UBT as any,
  hbridge: hbridge as any,
  systemCode: isWechatMini ? '64' : '63',
  token: storeManager.token,  // 使用创建时的 token
});

// 在函数中使用
const handlePayment = (payParams: any, returnUrl: string) => {
  return h5Pay.pay({
    payParams,
    // ...
  });
};

中间想法:模块加载时创建,但是重新传入token

虽然传入最新 token,但实例是旧的,只是针对方法pay传入了最新的token

// 在模块顶层,模块加载时立即创建
const h5Pay = new H5Pay({
  env: getAppEnv(),
  ubt: UBTHelper.UBT as any,
  hbridge: hbridge as any,
  systemCode: isWechatMini ? '64' : '63',
  token: storeManager.token,  // 使用创建时的 token
});

// 在函数中使用
const handlePayment = (payParams: any, returnUrl: string) => {
  return h5Pay.pay({
    // !!!虽然传入最新 token,但实例是旧的,只是针对方法pay传入了最新的token
    token: storeManager.token,
    payParams,
    // ...
  });
};

方式二:调用时创建(现在的方式)

// 创建实例的函数
const getH5PayInstance = () => {
  return new H5Pay({
    env: getAppEnv(),
    ubt: UBTHelper.UBT as any,
    hbridge: hbridge as any,
    systemCode: isWechatMini ? '64' : '63',
    token: storeManager.token,  // 每次创建时使用最新的 token
  });
};

// 在函数中使用
const handlePayment = (payParams: any, returnUrl: string) => {
  const h5Pay = getH5PayInstance();  // 每次调用时创建新实例
  return h5Pay.pay({
    payParams,
    // ...
  });
};

二、方式一:模块加载时创建

✅ 优点

  1. 性能优势
    • 实例只创建一次,减少对象创建开销
    • 内存占用更少(单例模式)
    • 适合频繁调用的场景
  1. 初始化时机明确
    • 在模块加载时完成初始化
    • 如果初始化失败,会在应用启动时暴露问题
    • 便于调试和排查问题
  1. 代码简洁
    • 不需要额外的函数封装
    • 直接使用常量,代码更直观

❌ 缺点

  1. 配置可能过期
    • token 在创建时固定,后续 token 更新不会反映到实例中
    • 虽然可以在 pay() 方法中传入新 token,但实例本身的配置可能已过期
    • 如果 H5Pay 内部缓存了 token,可能导致使用过期 token
  1. 环境变量固定
    • envsystemCode 等在创建时确定
    • 如果运行时环境变化,实例不会更新
    • 例如:从开发环境切换到生产环境
  1. 路由参数固定
    • isWechatMini 在模块加载时判断
    • 如果用户在不同环境间切换,判断可能不准确
  1. 内存泄漏风险
    • 如果 H5Pay 实例持有大量资源或监听器
    • 单例模式可能导致资源无法释放

三、方式二:调用时创建

✅ 优点

  1. 配置始终最新
    • 每次调用都使用最新的 token
    • 用户重新登录后,下次支付会使用新 token
    • 避免 token 过期导致的支付失败
  1. 环境动态适应
    • envsystemCode 等每次都是最新值
    • 适应运行时环境变化
    • 更灵活,适合多环境场景
  1. 路由参数准确
    • isWechatMini 在调用时判断,更准确
    • 适应不同页面、不同环境的需求
  1. 资源管理更好
    • 每次创建新实例,旧实例可以被 GC 回收
    • 避免长期持有资源导致的内存问题

❌ 缺点

  1. 性能开销
    • 每次调用都创建新实例,增加对象创建开销
    • 如果支付调用频繁,可能影响性能
    • 内存占用可能更多(虽然旧实例会被回收)
  1. 初始化失败时机不确定
    • 初始化失败可能在用户支付时才发现
    • 用户体验较差(支付时才发现问题)
    • 需要更好的错误处理
  1. 代码复杂度稍高
    • 需要额外的 getH5PayInstance() 函数
    • 代码稍微复杂一些

四、总结对比表

对比项方式一:模块加载时创建方式二:调用时创建
性能✅ 更好(单例,只创建一次)⚠️ 稍差(每次创建)
配置准确性❌ 可能过期✅ 始终最新
Token 更新❌ 可能使用旧 token✅ 使用最新 token
环境适应❌ 固定✅ 动态适应
内存占用✅ 更少⚠️ 稍多(但可回收)
代码复杂度✅ 更简单⚠️ 稍复杂
错误发现时机✅ 启动时❌ 支付时
适用场景配置不变、高频调用配置可能变化、准确性要求高