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

JS中如何按顺序调用POST路由函数串行拉取API数据

问题根因

执行顺序错乱的核心原因非常明确:async 声明的函数返回值是 Promise,你在路由回调里调用 getGeoNamesData() 时没有加 await 等待异步请求 resolve,JS 事件循环会直接跳过 pending 状态的 Promise 继续往下执行同步代码,才会出现日志顺序完全不符合预期、经纬度变量还没赋值就被后续接口调用的问题。
另外原有代码还存在两个隐藏风险:

  • longitude/latitude/userInput 用全局变量存储,并发请求时会出现变量覆盖的脏数据问题
  • 所有异步接口请求没有统一错误兜底,流程结束后也没有给前端返回响应,很容易导致请求挂起、进程异常崩溃

修改方案

核心调整逻辑

  1. 将路由回调改成 async 函数,所有依赖前置异步结果的调用前都加 await 等待,保证执行顺序符合预期
  2. 移除全局传参的写法,各个异步函数通过入参拿需要的参数,通过 return 返回执行结果,避免全局变量污染
  3. 加统一错误捕获,所有流程执行完成后主动给前端返回响应

修改后的完整可运行代码如下:

// 路由回调加async关键字,才能在内部使用await
app.post('/postUserInput', async function (req, res) {
  try {
    const currentWeatherUI = req.body.buildCurrentBoolean;
    const userInput = {
      userCityInput: req.body.userCityInput, 
      userStateInput: req.body.userStateInput, 
      userDateInput: req.body.userDateInput,
    };
    console.log("first");
    // 等待GeoNames接口返回结果,直接拿到经纬度,不依赖全局变量存储
    const { longitude, latitude } = await getGeoNamesData(userInput);
    console.log("second");

    console.log("third");
    if (currentWeatherUI) {
      await getCurrentWeatherbitData(longitude, latitude, userInput);
      console.log("fourth");
      console.log("fifth");
    } else {
      await getFutureWeatherbitData(longitude, latitude, userInput);
    };
    console.log("sixth");
    await getPixabayData(userInput);
    console.log("seventh");
    console.log("eigth");

    // 所有流程执行完成后,给前端返回组装好的结果
    res.status(200).send({
      code: 0,
      data: projectDataArray
    })
  } catch(err) {
    // 统一捕获所有环节的异常,给前端返回错误提示
    console.log("接口执行异常", err);
    res.status(500).send({
      code: -1,
      msg: "服务执行异常"
    })
  }
});

// 接收userInput入参,请求完成后直接返回经纬度
const getGeoNamesData = async (userInput) => {
  const response = await axios.get('http://api.geonames.org/searchJSON?q='+userInput.userCityInput+'+'+userInput.userStateInput+'&maxRows=1&username='+geonamesUser);
  return {
    longitude: response.data.geonames[0].lng,
    latitude: response.data.geonames[0].lat
  }
};

// 接收经纬度、用户输入入参,完成后把结果推入数据数组
const getCurrentWeatherbitData = async (longitude, latitude, userInput) => {
  const weatherbitURL = "http://api.weatherbit.io/v2.0/current?&lat="+latitude+"&lon="+longitude+"&key="+weatherbitUser+"&units=I&lang=en";
  const response = await axios.get(weatherbitURL);
  const newDayObject = {
    city: response.data.data[0].city_name,
    state: response.data.data[0].state_code,
    date: userInput.userDateInput,
    temp: response.data.data[0].temp,
    wind: response.data.data[0].wind_spd,
    windDirection: response.data.data[0].wind_cdir,
    rain: response.data.data[0].precip,
    snow: response.data.data[0].snow
  };
  projectDataArray.push(newDayObject);
};

// 未来天气查询函数和当前天气逻辑保持一致,补全入参接收、加await等待即可
const getFutureWeatherbitData = async (longitude, latitude, userInput) => {
  // 原有未来天气请求逻辑保留即可
};

// 接收用户输入入参,完成后把图片结果推入数据数组
const getPixabayData = async (userInput) => {
  const pixabayURL = "https://pixabay.com/api/?key="+pixabayUser+"&q="+userInput.userCityInput+"+"+userInput.userStateInput+"&image_type=photo&pretty=true&per_page=3";
  const response = await axios.get(pixabayURL);
  let cityImageObj;
  if (response.data.hits.length > 0) {
    cityImageObj = {cityImageURL: response.data.hits[0].webformatURL};
  } else {
    cityImageObj = {cityImageURL: "https://www.pennlive.com/resizer/vNu0aYjk3xlFTUb16FSrSji_DIA=/1280x0/smart/advancelocal-adapter-image-uploads.s3.amazonaws.com/image.pennlive.com/home/penn-media/width2048/img/life/photo/wintermeme11.jpg"};
  }
  projectDataArray.push(cityImageObj);
};

修改后效果

调整后控制台日志会严格按照 first -> second -> third -> fourth -> fifth -> sixth -> seventh -> eigth 的顺序打印,经纬度会在天气、图片接口调用前完成赋值,不会再出现参数为空的问题。如果需要优化接口性能,在拿到经纬度之后,天气查询和图片查询没有依赖关系,也可以用 Promise.all 并行执行两个请求,减少整体接口响应时间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:06:16