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

如何结合回调函数使用ember-concurrency实现批量地址验证?

解决ember-concurrency等待第三方回调API的问题

你的核心问题在于第三方API使用的是回调式异步模式,而ember-concurrency的task需要依赖Promise来感知异步操作的完成状态。目前你的BatchQueryAddresses方法没有返回任何值(默认返回undefined),所以yield之后自然拿到的是null/undefined。

解决思路很清晰:把回调风格的API包装成Promise,让task可以通过yield等待这个Promise完成,直到回调触发再继续执行。

第一步:修改ApiService,将回调API包装为Promise

重写BatchQueryAddresses方法,让它返回一个Promise,在Promise内部处理第三方API的回调逻辑:

import Service from '@ember/service';

export default class ApiService extends Service {
  _api;

  constructor() {
    super(...arguments);
    this._api = API;
  }

  BatchQueryAddresses(addressList) {
    // 返回一个新的Promise
    return new Promise((resolve, reject) => {
      // 定义回调函数,在第三方API完成后触发
      const handleCallback = (result, error) => {
        if (error) {
          // 出错时reject Promise,携带错误信息
          reject(new Error(`地址验证失败: ${result}`));
        } else {
          // 成功时resolve Promise,返回格式化后的结果
          const formattedResult = JSON.stringify(result, null, ' ');
          resolve(formattedResult);
        }
      };

      // 调用第三方API,传入我们的回调函数
      this._api.BatchQueryAddress(addressList, 2, handleCallback, null, 2000);
    });
  }
}

这样修改后,BatchQueryAddresses就变成了一个返回Promise的方法,ember-concurrency的task可以正确等待它完成。

第二步:更新Component中的task,处理Promise结果

现在你的task可以通过yield等待Promise,并通过try/catch处理成功和错误情况:

import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';

export default class BatchAddressInputComponent extends Component {
  @service api;
  addressList = ""; // 从TextArea获取的地址列表

  @task *DoAddressValidation () {
    try {
      // yield会等待Promise resolve后才继续执行
      let results = yield this.api.BatchQueryAddresses(this.addressList);
      alert(results); // 现在能拿到正确的验证结果了
    } catch (error) {
      // 捕获Promise reject的错误
      alert(error.message);
    }
  }
}

为什么这样可行?

ember-concurrency的task对Promise有原生支持:当你yield一个Promise时,task会暂停执行,直到这个Promise被resolve或reject。如果Promise resolve,task会继续执行并拿到resolve的值;如果Promise reject,task会抛出错误,你可以用try/catch捕获并处理。

额外提示(可选)

如果你的第三方API支持取消正在进行的请求,你还可以利用ember-concurrency的task取消机制,在task被取消时调用API的取消方法,避免不必要的资源消耗。比如:

BatchQueryAddresses(addressList, cancelToken) {
  return new Promise((resolve, reject) => {
    const handleCallback = (result, error) => {
      if (cancelToken.isCancelled) return;
      // ... 原有逻辑
    };

    const requestId = this._api.BatchQueryAddress(addressList, 2, handleCallback, null, 2000);
    
    // 当cancelToken触发取消时,调用API的取消方法
    cancelToken.add(() => {
      this._api.CancelBatchQuery(requestId);
    });
  });
}

然后在task中使用yield this.api.BatchQueryAddresses(this.addressList, this.DoAddressValidation.cancelToken)即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:53:13