如何在 JavaScript 中正确返回并解构多个函数值(含异步处理详解)

本文详解为何 `createinvoice()` 返回 `undefined` 导致解构失败,并提供 promise 封装、async/await 改写及错误处理的完整解决方案,助你安全获取 paypal 发票 id、状态、付款人等多值结果。

你遇到的错误:

TypeError: createInvoice is not a function or its return value is not iterable

根本原因在于:createInvoice 是一个异步函数,但当前实现中并未真正返回任何值。你写在 paypal.invoice.create(..., function (error, invoice) { ... }) 回调内的 return [...],只返回给了这个内部回调函数,而非 createInvoice 本身——因此 createInvoice() 的返回值始终是 undefined。而 const [a, b, c] = undefined 在 JavaScript 中会直接抛出“not iterable”错误。

✅ 正确做法:用 Promise 封装异步操作

将基于回调(callback)的 paypal.invoice.create 改造成返回 Promise 的函数,才能支持 await 和数组解构:

function createInvoice(item_name, note_message, quantity, cost, payer_email) {
  return new Promise((resolve, reject) => {
    const create_invoice_json = {
      merchant_info: {
        email: config.emailAddress,
        business_name: config.business_name,
      },
      billing_info: [{ email: payer_email }],
      items: [
        {
          name: item_name,
          quantity: parseInt(quantity, 10),
          unit_price: {
            currency: "USD",
            value: parseFloat(cost).toFixed(2), // 确保金额格式合规
          },
        },
      ],
      note: note_message,
    };

    paypal.invoice.create(create_invoice_json, (error, invoice) => {
      if (error) {
        console.error("PayPal invoice creation failed:", error);
        reject(error);
      } else {
        // ✅ 安全提取字段(避免 undefined 访问)
        const id = invoice?.id || null;
        const status = invoice?.status || "unknown";
        const payer = invoice?.

billing_info?.[0] || {}; const firstItem = invoice?.items?.[0] || {}; const secondItem = invoice?.items?.[1] || null; // 注意:可能不存在 const invoiceDate = invoice?.invoice_date || new Date().toISOString(); const totalValue = invoice?.total_amount?.[1]?.value || "0.00"; resolve([id, status, payer, firstItem, secondItem, invoiceDate, totalValue]); } }); }); }

✅ 调用方式:使用 await + 解构(需在 async 函数内)

// ✅ 必须在 async 上下文中调用
async function handleInvoiceCommand() {
  try {
    const [id, status, payer, item, secondItem, date, price] = 
      await createInvoice(item_name, note_message, quantity, cost, payer_email);

    console.log("Invoice created:", { id, status, payerEmail: payer.email, date });

    // 这里可继续发送 Discord 响应等逻辑
    // interaction.reply(`✅ Invoice #${id} created! Status: ${status}`);

  } catch (err) {
    console.error("Failed to create invoice:", err);
    // interaction.reply("❌ Failed to generate invoice. Please try again.");
  }
}

⚠️ 关键注意事项

  • 不要在顶层或非 async 函数中直接 await ——会报语法错误;
  • 始终校验嵌套属性(如 invoice?.items?.[0]),避免 Cannot read property '0' of undefined;
  • ? invoice.items[1] 很可能不存在(你的 JSON 只传入 1 个 item),建议改用 invoice.items.length > 1 ? invoice.items[1] : null;
  • ? total_amount[1] 非标准 PayPal 字段(常见为 total_amount.value 或 total_amount.currency),请以 PayPal Invoices API 文档 为准,推荐改为:
    const totalAmount = invoice?.total_amount?.value || "0.00";
    const totalCurrency = invoice?.total_amount?.currency || "USD";
    resolve([id, status, payer, firstItem, null, invoiceDate, totalAmount, totalCurrency]);
  • ? 若需兼容旧版 Node.js(

✅ 总结

问题根源 解决方案
回调内 return 不等于函数返回值 将函数改造成返回 Promise
直接解构 undefined 报错 使用 await 等待 Promise resolve 后再解构
潜在 undefined 字段访问 全面使用可选链(?.)和空值合并(??)防护
错误未被捕获导致进程崩溃 try/catch 包裹 await,避免 unhandled rejection

遵循以上模式,你的 createInvoice() 就能真正返回可解构的值,同时保持健壮性与可维护性。