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

循环调用含Promise的async函数后后续代码无法执行求助

问题分析与修复方案

首先,你的问题核心在于getProps函数的Promise结构存在两个关键问题:冗余的Promise嵌套和错误处理缺失,这导致当await this.view.getProps(id)执行时,一旦某个调用出现异常或者Promise未正确resolve/reject,整个循环会被卡住,后续代码(比如console.log("Hello"))永远无法执行。

问题拆解

先看你的getProps函数:

async getProps(dbId) { 
  const properties = Viewer.properties //creates an empty map 
  return new Promise((resolve, reject) => { 
    let prom = new Promise((resolve, reject) => { 
      this.gui.getProperties( 
        dbId, 
        args => { 
          console.log('properties', args) 
          resolve(args.properties) 
        }, 
        reject 
      ) 
    }) 
    prom.then(props => { 
      properties.set(dbId, props) 
      resolve(properties.entries()) 
    }) 
    console.log('properties', properties) 
  }) 
}
  1. 冗余的Promise嵌套:你已经在外层创建了一个Promise,里面又嵌套了另一个Promise,完全没必要,反而增加了复杂度。
  2. 错误处理漏洞:虽然你把reject传给了getProperties的失败回调,但外层Promise的reject并没有被正确关联——如果getProperties调用失败,内层Promise会reject,但外层Promise的reject从未被调用,导致这个Promise永远处于pending状态,await会一直等待下去,循环卡住。
  3. 返回值问题:properties.entries()返回的是Map迭代器,而不是你期望的“以ID为键、属性数组为值的映射”,虽然你说能打印,但迭代器并不是一个可直接使用的对象,可能后续处理会有问题。

修复后的getProps函数

我们可以简化Promise结构,正确处理resolve和reject,同时确保返回的是完整的Map(或者你需要的对象):

async getProps(dbId) {
  // 确保Viewer.properties是一个Map,如果每次调用需要独立映射,就改为new Map()
  const properties = Viewer.properties || new Map();
  return new Promise((resolve, reject) => {
    this.gui.getProperties(
      dbId,
      (args) => {
        console.log('properties', args);
        properties.set(dbId, args.properties);
        // 返回完整的Map,而不是迭代器,方便调用方直接使用
        resolve(properties);
      },
      (error) => {
        console.error('Failed to get properties for dbId:', dbId, error);
        // 必须调用reject,否则Promise会一直处于pending状态
        reject(error);
      }
    );
  });
}

修复点说明:

  • 去掉了冗余的内层Promise,直接用外层Promise包装getProperties的回调逻辑。
  • 明确处理失败回调,调用外层的reject,确保Promise不会一直挂起。
  • 返回完整的properties Map,替代迭代器,让调用方可以直接使用get(id)或者转为普通对象。

修复调用逻辑

在getConcreteIds中,await会等待每个getProps完成,一旦某个调用失败,整个async函数会抛出错误,导致后续代码不执行。建议添加try/catch处理异常,确保循环能继续执行:

async getConcreteIds() {
  let wallfloorids = this.getWallIds().concat(this.getFloorIds());
  // 用于收集所有成功获取的属性映射
  const concretePropsMap = new Map();
  
  for(let id of wallfloorids) {
    try {
      let propsMap = await this.view.getProps(id);
      console.log(propsMap);
      // 将当前ID的属性存入全局收集Map
      concretePropsMap.set(id, propsMap.get(id));
    } catch (error) {
      console.error('Failed to process dbId:', id, error);
      // 跳过错误ID,继续处理下一个
      continue;
    }
  }
  
  console.log("Hello");
  // 返回最终的属性映射
  return concretePropsMap;
}

调用逻辑说明:

  • 用try/catch包裹每个await调用,即使某个ID处理失败,循环也会继续执行,不会卡住整个流程。
  • 单独收集成功的结果,方便后续业务逻辑使用。

额外优化建议

如果Viewer.properties是全局共享的Map,多次调用getProps会持续往里面添加数据,这可能符合你的预期;但如果每次调用需要独立的映射,应该在getProps里创建新的Map():

const properties = new Map(); // 替代复用Viewer.properties

这样调整后,你的循环会正常执行完所有52个ID,后续的console.log("Hello")也会正常打印,同时能得到你期望的ID-属性映射。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:04:29