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

购物车Fetch更新时代金券商品数量与价格无法即时同步的修复求助

购物车Fetch更新时代金券商品数量与价格无法即时同步的修复求助

各位开发者大佬好,我在Shopify项目里开发购物车商品数量更新功能时,遇到了一个同步延迟的问题,想请大家帮忙看看怎么解决。

先简单说下背景:我基于现有的购物车数量更新逻辑(用fetch()调用cart_change_url),加了一个关联逻辑——当用户更新需要配套代金券的商品数量时,自动同步调整对应代金券的数量。

现在的问题是:代金券的数量和价格变化,无法在用户操作后即时显示在页面上,必须要等下一次操作(比如再改一次数量)才会更新,相当于页面显示总是慢一步。

下面是我的完整代码和修改部分:

完整的更新函数代码

updateMainItem(line, quantity, name, variantId) {
  const body = JSON.stringify({
    line,
    quantity,
    sections: this.getSectionsToRender().map((section) => section.section),
    sections_url: window.location.pathname,
  });
  fetch(`${routes.cart_change_url}`, {
    ...fetchConfig(),
    ...{ body }
  })
  .then((response) => {
    return response.text();
  })
  .then((state) => {
    const parsedState = JSON.parse(state);
    const quantityElement = document.getElementById(`Quantity-${line}`) || document.getElementById(`Drawer-quantity-${line}`);
    const items = document.querySelectorAll('.cart-item');
    // 👇 我的修改部分开始
    const itemsNeedingVouchers = parsedState.items.filter((i) => i.properties?.Vouchers === "Yes");
    const vouchers = parsedState.items.filter((i) => i.variant_id === 46396120596724);
    if (itemsNeedingVouchers && vouchers) {
      const updateVoucher = async (id, quantity) => {
        await fetch("/cart/update.js", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ updates: { [id]: quantity } }),
        })
        .then((response) => { return response.text(); })
        .then((responseText) => {});
      };
      for (const item of itemsNeedingVouchers) {
        const voucher = vouchers.find(v => v.properties?.["For Variant"] === String(item.id));
        if (voucher) {
          updateVoucher(voucher.id, item.quantity);
        } else {
          updateVoucher(voucher.id, 0);
        }
      }
    }
    // 👇 我的修改部分结束
    if (parsedState.errors) {
      quantityElement.value = quantityElement.getAttribute('value');
      this.updateLiveRegions(line, parsedState.errors);
      return;
    }
    this.classList.toggle('is-empty', parsedState.item_count === 0);
    const cartDrawerWrapper = document.querySelector('cart-drawer');
    const cartFooter = document.getElementById('main-cart-footer');
    if (cartFooter) cartFooter.classList.toggle('is-empty', parsedState.item_count === 0);
    if (cartDrawerWrapper) cartDrawerWrapper.classList.toggle('is-empty', parsedState.item_count === 0);
    this.getSectionsToRender().forEach((section) => {
      const elementToReplace = document.getElementById(section.id).querySelector(section.selector) || document.getElementById(section.id);
      elementToReplace.innerHTML = this.getSectionInnerHTML(
        parsedState.sections[section.section],
        section.selector
      );
    });
    const updatedValue = parsedState.items[line - 1] ? parsedState.items[line - 1].quantity : undefined;
    let message = '';
    if (items.length === parsedState.items.length && updatedValue !== parseInt(quantityElement.value)) {
      if (typeof updatedValue === 'undefined') {
        message = window.cartStrings.error;
      } else {
        message = window.cartStrings.quantityError.replace('[quantity]', updatedValue);
      }
    }
    this.updateLiveRegions(line, message);
    const lineItem = document.getElementById(`CartItem-${line}`) || document.getElementById(`CartDrawer-Item-${line}`);
    if (lineItem && lineItem.querySelector(`[name="${name}"]`)) {
      cartDrawerWrapper ? trapFocus(cartDrawerWrapper, lineItem.querySelector(`[name="${name}"]`)) : lineItem.querySelector(`[name="${name}"]`).focus();
    } else if (parsedState.item_count === 0 && cartDrawerWrapper) {
      trapFocus(cartDrawerWrapper.querySelector('.drawer__inner-empty'), cartDrawerWrapper.querySelector('a'));
    } else if (document.querySelector('.cart-item') && cartDrawerWrapper) {
      trapFocus(cartDrawerWrapper, document.querySelector('.cart-item__name'));
    }
    publish(PUB_SUB_EVENTS.cartUpdate, { source: 'cart-items', cartData: parsedState, variantId: variantId });
  })
  .catch(() => {
    this.querySelectorAll('.loading__spinner').forEach((overlay) => overlay.classList.add('hidden'));
    const errors = document.getElementById('cart-errors') || document.getElementById('CartDrawer-CartErrors');
    errors.textContent = window.cartStrings.error;
  })
  .finally(() => {
    this.disableLoading(line);
  });
}

问题分析

我自己排查了一下,觉得问题应该出在异步请求的时序上:

  • 页面的UI更新是基于第一次cart_change_url返回的parsedState,这时代金券的数量还没更新;
  • 代金券的更新是在之后的异步fetch('/cart/update.js')请求里,等这个请求完成时,页面已经完成了第一次渲染,所以最新的代金券状态没有同步到页面上;
  • 只有等下一次操作触发更新时,才会拿到包含代金券最新状态的购物车数据,页面才会显示正确的信息。

我尝试过的思路

我想过把代金券的更新改成同步,但await在原来的回调里好像没起作用,或者我用的方式不对?也想过在代金券更新完成后手动触发页面重新渲染,但不知道怎么调用现有的sections更新逻辑。

有没有大佬能帮我调整代码,让代金券的数量和价格能在用户操作后即时显示出来?


内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 06:45:26