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

函数内执行Ajax Call失效并抛出警告,如何解决?

Ajax调用DRY优化后的问题排查与解决

问题背景

尝试对包含多个Ajax调用的JavaScript文件进行DRY(Don't Repeat Yourself)优化,编写了makeCall函数统一发起Ajax调用,但修改后出现两个问题:

  • 调用retrieveCountry.php的第二个makeCall未执行(GeoJSON要素未添加到地图)
  • TypeScript警告:'await' has no effect on the type of this expression.ts(80007)

所有代码位于一个async函数内,detail为该函数的局部变量。

原可正常运行的代码

const makeCall = (url, type, data, done) => {
    $.ajax({
            url: url,
            type: type,
            dataType: "json",
            data: data,
        })
        .done(done)
        .fail(function(error) {
            console.log(error);
        });
};

const country = await $.ajax({
        url: "libs/php/opencage.php",
        type: "GET",
        dataType: "json",

        data: {
            LAT: x.coords.latitude,
            LNG: x.coords.longitude,
        },
    })
    .done(function(result) {
        if (result.status.name == "ok") {
            //populate the detail object with responses from opencage needed to communicate with other apis
            detail.lat = x.coords.latitude;
            detail.long = x.coords.longitude;
            detail.continent = result.data.results[0].components.continent;
            detail.countryName = result.data.results[0].components.country;
            detail.countryCode = result.data.results[0].components.country_code;

            let code = result.data.results[0].components.country_code;
            //set the select to user country
            console.log(code);
            $("#countrySelect").val(code.toUpperCase());
        }
    })
    .fail(function(error) {
        // your error code

        console.log(error);
    });

//save needed part of detail object for easy access
let latitude = detail.lat;
let longitude = detail.long;
let countryName = noSpace(detail.countryName);
let countryCode = detail.countryCode;
let continent = detail.continent;

//makecall to retrieve geojson feature details for selected country.
makeCall(
    "libs/php/retrieveCountry.php",
    "GET", {
        code: countryCode.toUpperCase()
    },
    function(r) {
        //add the geojson object to the map
        L.geoJSON(r).addTo(map);
    }
);

修改后出现问题的代码

const country = await makeCall(
    "libs/php/opencage.php",
    "GET", {
        LAT: x.coords.latitude,
        LNG: x.coords.longitude,
    },
    function(result) {
        if (result.status.name == "ok") {
            //populate the detail object with responses from opencage needed to communicate with other apis
            detail.lat = x.coords.latitude;
            detail.long = x.coords.longitude;
            detail.continent = result.data.results[0].components.continent;
            detail.countryName = result.data.results[0].components.country;
            detail.countryCode = result.data.results[0].components.country_code;

            let code = result.data.results[0].components.country_code;
            //set the select to user country
            console.log(code);
            $("#countrySelect").val(code.toUpperCase());
            return detail;
        }
    }
);

//save needed part of detail object for easy access
let latitude = detail.lat;
let longitude = detail.long;
let countryName = noSpace(detail.countryName);
let countryCode = detail.countryCode;
let continent = detail.continent;

//makecall to retrieve geojson feature details for selected country. This part is never implemented as this feature is not added to the map.
makeCall(
    "libs/php/retrieveCountry.php",
    "GET", {
        code: countryCode.toUpperCase()
    },
    function(r) {
        //add the geojson object to the map
        L.geoJSON(r).addTo(map);
    }
);

问题原因分析

  1. TypeScript警告原因:makeCall函数没有返回任何值(默认返回undefined),await对undefined没有等待效果,因此TS提示该警告。原代码中await $.ajax(...)有效是因为$.ajax本身返回Promise,但你封装的makeCall没有把这个Promise返回出来。

  2. 第二个makeCall未执行的原因:由于await makeCall(...)无效,代码会直接往下执行,此时第一个Ajax请求还未完成,detail对象的属性(比如countryCode)还未被赋值。后续给第二个makeCall传的参数code: countryCode.toUpperCase()会因为countryCode是undefined而抛出错误,导致第二个请求根本无法正常发起,或者后端接收到无效参数后返回错误,而你没注意到fail里的日志。另外,done回调里的return detail没有任何作用,因为这个返回值不会被makeCall传递出来。

解决方案

步骤1:修改makeCall函数,让它返回Promise

调整makeCall,直接返回$.ajax生成的Promise,这样await就能正确等待请求完成:

const makeCall = (url, type, data) => {
  return $.ajax({
    url: url,
    type: type,
    dataType: "json",
    data: data,
  }).fail(function(error) {
    console.log(error);
  });
};

步骤2:调整调用逻辑,用await替代回调

把原来done回调里的逻辑移到await之后,直接处理请求返回的结果:

// 等待第一个请求完成,拿到结果
const result = await makeCall(
  "libs/php/opencage.php",
  "GET",
  {
    LAT: x.coords.latitude,
    LNG: x.coords.longitude,
  }
);

if (result.status.name == "ok") {
  // 填充detail对象
  detail.lat = x.coords.latitude;
  detail.long = x.coords.longitude;
  detail.continent = result.data.results[0].components.continent;
  detail.countryName = result.data.results[0].components.country;
  detail.countryCode = result.data.results[0].components.country_code;

  let code = result.data.results[0].components.country_code;
  console.log(code);
  $("#countrySelect").val(code.toUpperCase());
}

// 此时detail属性已被正确赋值
let latitude = detail.lat;
let longitude = detail.long;
let countryName = noSpace(detail.countryName);
let countryCode = detail.countryCode;
let continent = detail.continent;

// 第二个请求现在能拿到正确的参数,正常执行
await makeCall(
  "libs/php/retrieveCountry.php",
  "GET",
  {
    code: countryCode.toUpperCase()
  }
).then(function(r) {
  L.geoJSON(r).addTo(map);
});

额外说明

如果需要保留makeCall的回调参数(兼容原有调用方式),可以让它同时支持Promise和回调:

const makeCall = (url, type, data, done) => {
  const promise = $.ajax({
    url: url,
    type: type,
    dataType: "json",
    data: data,
  }).fail(function(error) {
    console.log(error);
  });

  if (done) {
    promise.done(done);
  }

  return promise;
};

这样既可以用await调用,也可以继续用回调方式调用,兼顾新旧代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:07:01