每个Promise的超时未重置问题求助(Mapbox地图下载场景)
问题根源
你当前代码的核心问题在于:bufferedCellBBoxes.map会同步遍历所有单元格,一次性为每个cell创建60秒超时定时器——所有定时器在同一时刻启动计时。哪怕某个cell的下载在10秒内完成,对应的定时器依然会继续运行,到点后触发超时逻辑;同时你没有在下载完成时标记超时已处理,导致定时器回调仍会执行,进而出现“频繁触发超时”的现象。
修复方案
方案1:完善超时标记+清除定时器
在下载完成或出错时,立即标记超时已处理并主动清除定时器,彻底避免后续无效的超时回调:
const downloads = bufferedCellBBoxes.map(async (cell, i) => { let timeoutResolved = false; let timeoutId; // 保存定时器ID const timeoutPromise = new Promise((resolve) => { timeoutId = setTimeout(() => { if (!timeoutResolved) { resolve('timeout'); timeoutResolved = true; } }, 60000); }); const satellitePromise = downloadMapTiles( 'satellite', [[cell[2] as number, cell[3] as number], [cell[0] as number, cell[1] as number]], ); const streetPromise = downloadMapTiles( 'street', [[cell[2] as number, cell[3] as number], [cell[0] as number, cell[1] as number]], ); try { const result = await Promise.race([ Promise.all([satellitePromise, streetPromise]), timeoutPromise, ]); timeoutResolved = true; clearTimeout(timeoutId); // 下载完成,清除定时器 if (result === 'timeout') { throw new Error('Timed out'); } return result; } catch (error) { timeoutResolved = true; clearTimeout(timeoutId); // 出错时也清除定时器 console.error(`Cell ${i} download error:`, error); return Promise.reject(error); } });
方案2:串行处理单元格(逐一下载)
如果你的“每一轮循环”指串行执行下载(完成一个cell再处理下一个),而非并行下载所有,那么不能用map批量启动任务,改用循环串行执行:
async function downloadAllCells() { const results = []; for (const [i, cell] of bufferedCellBBoxes.entries()) { let timeoutResolved = false; let timeoutId; const timeoutPromise = new Promise((resolve) => { timeoutId = setTimeout(() => { if (!timeoutResolved) { resolve('timeout'); timeoutResolved = true; } }, 60000); }); const satellitePromise = downloadMapTiles( 'satellite', [[cell[2] as number, cell[3] as number], [cell[0] as number, cell[1] as number]], ); const streetPromise = downloadMapTiles( 'street', [[cell[2] as number, cell[3] as number], [cell[0] as number, cell[1] as number]], ); try { const result = await Promise.race([ Promise.all([satellitePromise, streetPromise]), timeoutPromise, ]); timeoutResolved = true; clearTimeout(timeoutId); if (result === 'timeout') { throw new Error('Timed out'); } results.push(result); } catch (error) { timeoutResolved = true; clearTimeout(timeoutId); console.error(`Cell ${i} download error:`, error); throw error; // 如需终止后续下载则抛出,否则替换为continue } } return results; } // 启动串行下载 downloadAllCells() .then(results => console.log('All downloads completed:', results)) .catch(err => console.error('Download process failed:', err));
内容的提问来源于stack exchange,提问作者MomasVII
相关产品推荐
相关产品推荐

