PAYATHON 2026

自定义交易组件商详下单一体回调中如何等待request返回?

支付老李

结论

setDetailOrderInfoChangeCallback 回调中可以发起 request。真正的问题是网络请求会异步执行:外层回调已经 return 后,请求的 success 回调或 Promise 才完成。因此,控制台会依次打印:

  1. 下单页面回调
  2. callbackData
  3. response

要让组件等待请求结果,外层回调必须返回 Promise,并在运费、商家优惠等请求全部完成后再 resolve。使用 async/await 时,需要先 await 请求结果,再 return 最终数据。

原因

下面的写法无法等待请求完成:

setDetailOrderInfoChangeCallback((callbackData) => {
  let result

  wx.request({
    url: 'https://example.com/order/calculate',
    data: callbackData,
    success(res) {
      console.log('response', res)
      result = res.data
    }
  })

  console.log('callbackData', callbackData)
  return result
})

wx.request 发起请求后,程序会立即执行后面的代码。此时 success 还没有触发,result 仍是 undefined,外层回调却已经结束了。

在 success 中写 return res.data 同样无效,因为这个值是从 success 函数返回的,并不会成为 setDetailOrderInfoChangeCallback 外层回调的返回值。

推荐写法:将请求封装为 Promise

先将 wx.request 包装成 Promise:

function request(options) {
  return new Promise((resolve, reject) => {
    wx.request({
      ...options,
      success(res) {
        resolve(res)
      },
      fail(err) {
        reject(err)
      }
    })
  })
}

然后在回调中使用 async/await:

setDetailOrderInfoChangeCallback(async (callbackData) => {
  console.log('下单页面回调')
  console.log('callbackData', callbackData)

  try {
    const response = await request({
      url: 'https://example.com/order/calculate',
      method: 'POST',
      data: callbackData
    })

    console.log('response', response)

    if (response.statusCode < 200 || response.statusCode >= 300) {
      throw new Error(`请求失败,statusCode: ${response.statusCode}`)
    }

    const orderInfo = response.data

    return {
      // 按组件文档要求组装返回值
      // freight: orderInfo.freight,
      // merchantDiscount: orderInfo.merchantDiscount
    }
  } catch (error) {
    console.error('查询运费和商家优惠失败', error)

    return {
      // 按组件约定返回兜底数据或错误信息
    }
  }
})

async 函数会自动返回 Promise。代码执行到 await request(...) 时,会先等待请求完成,再继续组装并返回结果。

返回对象的字段必须与当前组件文档中的定义一致。由于问题没有提供组件版本和返回协议,这里不补充具体字段。

同时查询运费和优惠

如果运费和商家优惠来自两个相互独立的接口,可以用 Promise.all 并行请求:

setDetailOrderInfoChangeCallback(async (callbackData) => {
  try {
    const [freightResponse, discountResponse] = await Promise.all([
      request({
        url: 'https://example.com/order/freight',
        method: 'POST',
        data: callbackData
      }),
      request({
        url: 'https://example.com/order/discount',
        method: 'POST',
        data: callbackData
      })
    ])

    return {
      // 按组件要求转换并返回数据
      // freight: freightResponse.data,
      // merchantDiscount: discountResponse.data
    }
  } catch (error) {
    console.error('订单信息计算失败', error)

    return {
      // 返回符合组件协议的兜底结果
    }
  }
})

如果优惠金额依赖运费结果,就需要串行请求:

setDetailOrderInfoChangeCallback(async (callbackData) => {
  const freightResponse = await request({
    url: 'https://example.com/order/freight',
    method: 'POST',
    data: callbackData
  })

  const discountResponse = await request({
    url: 'https://example.com/order/discount',
    method: 'POST',
    data: {
      ...callbackData,
      freight: freightResponse.data
    }
  })

  return {
    // 按组件协议组装最终返回值
  }
})

不使用 async/await 的写法

也可以直接返回 Promise:

setDetailOrderInfoChangeCallback((callbackData) => {
  return request({
    url: 'https://example.com/order/calculate',
    method: 'POST',
    data: callbackData
  }).then((response) => {
    console.log('response', response)

    return {
      // 按组件协议组装返回值
    }
  }).catch((error) => {
    console.error('查询失败', error)

    return {
      // 按组件协议返回兜底结果
    }
  })
})

是否使用 async/await 并不重要。需要保证的是,最外层回调必须将表示请求完成状态的 Promise 返回给组件。

注意事项

  • 不要在请求发出后立即返回一个尚未赋值的变量。
  • 不要只在 success 回调中写 return,这个返回值无法传递给外层回调。
  • 确认项目中的 request 封装确实返回了 Promise。有些请求函数虽然名称相同,内部却没有 return new Promise(...)。
  • 请求失败、超时或返回非成功状态码时,也要提供符合组件协议的返回值,避免下单页面一直等待。
  • 商品数量、规格或地址发生变化时,这个回调可能被频繁触发。必要时可以使用请求序号或取消机制,防止先发出的请求后返回,进而覆盖最新的计算结果。
  • 如果当前版本的组件明确规定回调只能同步返回,不接受 Promise,就无法在回调内等待网络请求,只能提前请求并缓存结果。组件是否支持 Promise,应以当前版本的官方接口定义为准。

备注:内容仅供参考。