NodeJS中批量调用Google Ads API时Promise永远不结束问题求助
问题原因排查
- 最核心的原因是部分Promise永远没有被resolve或者reject,导致
Promise.all会一直等待所有Promise完成,永远不会进入后续的then或者catch回调。常见的触发场景有两种:- 某个接口请求成功后返回的
bodyAdsCampaign[0].results是空数组,此时for...in循环不会执行,里面的resolve逻辑永远触发不了 - 用
for...in遍历数组的行为不稳定,如果results数组存在非数字索引的自定义属性,你判断ii == arrlength的逻辑就永远不会成立,同样不会触发resolve
- 某个接口请求成功后返回的
- 次要问题:你现在用全局变量
objectArray存结果、每个Promise resolve全局数组的写法有并发风险,不如直接让每个Promise返回自己的处理结果,最后在Promise.all的回调里统一收集更稳妥。 - 小疏漏:你写
arr.map((key,item)的时候参数名写反了,map回调的第一个参数是当前遍历的数组元素,第二个才是索引,虽然不影响当前功能但属于不规范写法,修复时会一并调整。
修复方案
修改后的代码如下:
Promise.all( arr.map((customerId) => { return new Promise((resolve, reject) => { let costmicro = 0; request.post({ url: 'https://googleads.googleapis.com/v8/customers/'+customerId+'/googleAds:searchStream', headers: { 'Content-Type': 'application/json', }, json: { "query": "SELECT metrics.cost_micros FROM campaign WHERE segments.date DURING LAST_30_DAYS", } }, function (errAdsCampaign, httpResponseAdsCampaign, bodyAdsCampaign) { if (errAdsCampaign) { // 出错直接把错误抛出 return reject(errAdsCampaign); } // 先校验返回结果的结构合法性,避免空值报错 const results = bodyAdsCampaign?.[0]?.results; if (!Array.isArray(results)) { // 结果为空直接返回0消耗,不要让Promise挂住 return resolve({name: customerId, cost: 0}); } // 用forEach遍历数组代替for...in,逻辑更稳定 results.forEach(res => { costmicro += parseInt(res.metrics?.costMicros || 0, 10); }) // 遍历完成直接resolve当前项的结果,不需要依赖索引判断 resolve({name: customerId, cost: costmicro / 1000000}); }); }); }) ).then((objectArray)=>{ // 这里拿到的参数就是所有请求返回的结果组成的数组 console.log('done'); console.log(objectArray) }).catch((e) => { console.error(e); });
内容的提问来源于stack exchange,提问作者Stian Instebo
相关产品推荐
相关产品推荐

