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

JavaScript异步API调用问题:speechText未定义及代码重构咨询

没错,你猜的完全正确!这就是异步操作的时序问题——你的代码确实在API请求返回结果之前,就执行了return handlerInput.responseBuilder...这行语句,导致speechText还没被赋值就被使用,自然会报未定义的错误。

问题根源

request.get是基于回调函数的异步HTTP请求:当JavaScript执行到这行代码时,会把请求发送出去,然后立刻继续执行后面的return语句,不会等待API返回结果。只有当API响应回来后,才会调用你传入的回调函数去处理body并赋值给speechText,但这时候响应已经返回给Alexa了,根本没用到这个值。


重构方案:用Async/Await处理异步逻辑

要解决这个问题,我们需要让代码等待API返回结果后再构建响应。这里有两种常见的实现方式:

方式1:封装request为Promise

原生request库本身不支持Promise,但我们可以手动封装它,再用async/await等待结果:

const NumberIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest' && 
           handlerInput.requestEnvelope.request.intent.name === 'NumberIntent';
  },
  // 将handle标记为async函数,自动返回Promise
  async handle(handlerInput) {
    console.log('At NumberIntentHandler');
    let slotNum = handlerInput.requestEnvelope.request.intent.slots.number.value;
    const url = `http://numbersapi.com/${slotNum}`;
    console.log('url: ', url);

    // 封装request.get为Promise
    const getNumberFact = () => {
      return new Promise((resolve, reject) => {
        request.get(url, (error, response, body) => {
          if (error) {
            console.log('error: ', error);
            reject(error);
          } else {
            console.log('statusCode: ', response && response.statusCode);
            console.log('body: ', body);
            resolve(body);
          }
        });
      });
    };

    try {
      // 等待API返回结果后再赋值
      const speechText = await getNumberFact();
      console.log('speechText: ', speechText);

      // 拿到结果后再构建响应
      return handlerInput.responseBuilder
        .speak(speechText)
        .withSimpleCard('Here is your fact: ', speechText)
        .getResponse();
    } catch (error) {
      // 处理请求失败的异常情况
      const errorText = 'Sorry, I couldn\'t get a fact for that number right now.';
      return handlerInput.responseBuilder
        .speak(errorText)
        .withSimpleCard('Error', errorText)
        .getResponse();
    }
  }
};

方式2:使用支持Promise的HTTP库(比如axios)

如果可以更换依赖,用axios这类原生支持Promise的库会更简洁:
首先安装依赖:

npm install axios

然后修改代码:

const axios = require('axios');

const NumberIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest' && 
           handlerInput.requestEnvelope.request.intent.name === 'NumberIntent';
  },
  async handle(handlerInput) {
    console.log('At NumberIntentHandler');
    let slotNum = handlerInput.requestEnvelope.request.intent.slots.number.value;
    const url = `http://numbersapi.com/${slotNum}`;
    console.log('url: ', url);

    try {
      // 直接用await等待axios请求结果
      const response = await axios.get(url);
      const speechText = response.data;
      console.log('body: ', speechText);
      console.log('speechText: ', speechText);

      return handlerInput.responseBuilder
        .speak(speechText)
        .withSimpleCard('Here is your fact: ', speechText)
        .getResponse();
    } catch (error) {
      console.log('error: ', error);
      const errorText = 'Sorry, I couldn\'t get a fact for that number right now.';
      return handlerInput.responseBuilder
        .speak(errorText)
        .withSimpleCard('Error', errorText)
        .getResponse();
    }
  }
};

关键说明

  • 把handle方法标记为async,它会自动返回Promise,Alexa的Skill框架完全支持异步handler。
  • 使用await暂停代码执行,直到异步请求完成,确保speechText有值后再构建响应。
  • 添加try/catch块处理请求失败的情况,避免Skill因API错误崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:33:44