TypeScript中forEach循环内处理Promise 构造结果数组并等待全部请求完成
问题分析
- 你当前的代码核心问题在于,把
deferredPromise.resolve(results)放在了单次getPoints请求的回调中,第一个接口请求返回后就直接把整个Promise标记为完成,后续其他suite对应的接口请求还没执行完,所以拿到的结果不全。 - forEach是同步遍历逻辑,本身不会等待异步请求完成,你需要把所有
getPoints返回的Promise统一收集起来,用Q.all等待全部请求完成后再统一resolve结果,这个方案完全可以解决你的问题。
修复后的代码
import Q = require("q"); public static getTestResults(testcaseId: number): Promise<TestResult[]>{ let deferredPromise = Q.defer<TestResult[]>(); let testManagementRestClient: TestManagementRestClient.TestHttpClient4_1; testManagementRestClient = TestManagementRestClient.getClient(); testManagementRestClient.getSuitesByTestCaseId(testcaseId).then(suites => { // 收集所有getPoints请求的Promise const pointRequestPromises = suites.map(suite => { return testManagementRestClient.getPoints( suite.project.id, +suite.plan.id, suite.id, undefined, undefined, testcaseId.toString(), undefined, true, undefined, undefined ).then(points => { // 提前处理当前suite的points,转成目标格式 return points.map(point => ({ projectId: suite.project.id, runId: point.lastTestRun.id, configuration: point.configuration.name })); }); }); // 等待所有请求全部完成 Q.all(pointRequestPromises).then(allSuitePoints => { // 把二维结果数组拍平成一维的TestResult数组 // 若运行环境不支持flat方法,可替换为 const results = ([] as TestResult[]).concat(...allSuitePoints); const results = allSuitePoints.flat(); deferredPromise.resolve(results); }).catch(err => { // 捕获请求异常,整体标记为失败 deferredPromise.reject(err); }); }).catch(err => { deferredPromise.reject(err); }); return deferredPromise.promise; }
逻辑说明
- 用
Array.map替代forEach遍历suites,每个元素返回对应getPoints的Promise,最终得到所有异步请求的Promise数组 Q.all接收这个Promise数组,会等待数组内所有Promise全部成功后才触发回调,回调参数是每个Promise返回的结果组成的数组,顺序和输入的Promise顺序完全一致- 补充了全链路异常捕获逻辑,任意一步请求失败都会把整体Promise标记为失败,避免出现悬而未决的Promise
内容的提问来源于stack exchange,提问作者habib
相关产品推荐
相关产品推荐

