Angular 2中如何从GeoFire异步方法返回自定义对象数组Promise
解决GeoFire异步场景下返回Vendor对象数组的问题
首先,你的核心问题在于GeoFire的key_entered是异步事件驱动的——它会在查询到匹配位置时多次触发,而非一次性返回所有结果。直接在事件回调里创建Vendor对象,没法让外层的Promise正确返回完整数组。我们需要把这些异步结果统一收集,等查询完成后再resolve这个Promise。
下面是修正后的完整实现思路和代码:
步骤1:用Promise包裹整个查询流程
在函数内部返回一个新的Promise,把GeoFire的事件监听、结果收集、完成逻辑都放在这个Promise里处理。
步骤2:监听key_entered收集Vendor对象
每次触发key_entered时,创建对应的Vendor实例并添加到数组中。
步骤3:监听ready事件完成Promise
GeoFire的ready事件会在初始查询完成(所有匹配的键都已触发key_entered)时触发,这时我们就可以resolve收集到的Vendor数组,同时记得移除事件监听避免内存泄漏。
完整代码示例
getLocations(radius: number, coords: Array<number>): Promise<Vendor[]> { console.log('In get locations'); return new Promise((resolve, reject) => { const geoQuery = this.geoFire.query({ center: coords, radius: radius }); const vendors: Vendor[] = []; // 监听key_entered,收集Vendor对象 const keyEnteredListener = geoQuery.on('key_entered', (key, location, distance) => { console.log(`key ${key} distance ${distance}`); const vendor = new Vendor(); // 根据业务需求给Vendor赋值,比如ID、位置、距离等 vendor.id = key; vendor.location = location; vendor.distance = distance; // 其他属性初始化... vendors.push(vendor); }); // 监听ready事件,查询完成后返回结果 const readyListener = geoQuery.on('ready', () => { // 移除监听,避免内存泄漏 keyEnteredListener.cancel(); readyListener.cancel(); // 返回收集到的所有Vendor resolve(vendors); }); // 监听错误事件,处理异常情况 const errorListener = geoQuery.on('error', (error) => { // 清理所有监听 keyEnteredListener.cancel(); readyListener.cancel(); errorListener.cancel(); // 抛出错误 reject(error); }); }); }
额外注意事项
- 内存泄漏问题:必须在查询完成或出错时调用监听的
cancel()方法,否则这些监听器会一直驻留内存。 - 实时更新场景:如果需要实时获取后续进入查询范围的新Vendor,
ready事件只代表初始查询完成,后续key_entered还会触发。这种情况建议用Observable替代Promise,或者在函数里额外处理实时更新逻辑。 - Vendor详情补全:如果需要从Firebase数据库根据key获取Vendor的详细信息(比如名称、联系方式),可以在
key_entered回调里用async/await处理异步请求,示例如下:
const keyEnteredListener = geoQuery.on('key_entered', async (key, location, distance) => { console.log(`key ${key} distance ${distance}`); // 假设你有一个获取Vendor详情的异步方法 const vendorDetails = await this.fetchVendorDetails(key); const vendor = new Vendor(); vendor.id = key; vendor.location = location; vendor.distance = distance; vendor.name = vendorDetails.name; vendor.contact = vendorDetails.contact; vendors.push(vendor); });
这种情况下,ready事件触发时可能有些详情请求还没完成,需要用Promise.all等待所有异步请求结束后再resolve数组,调整逻辑即可。
内容的提问来源于stack exchange,提问作者kpvsrkp
相关产品推荐
相关产品推荐

