javascript - 异步循环不尊重异步
问题描述
我有点卡在异步功能上。
我要完成的工作- 我正在创建一个批处理函数(batchGetSubs),它将遍历一组文件,读取一个 ID,然后发出 API 请求,等待响应(THE ISSUE),然后写入一个新的带有格式化数据的文件。
问题- 我已经尝试了 Async 和 Await,以及推送承诺并尝试使用 Promise.all 来等待承诺得到解决,但没有成功。当前的行为是,在 API 调用实际返回所有数据之前,我获得了 Promise.all 部分中的所有 console.logs。我使用这些文章作为参考:
守则——
async function batchGetSubs(data, command) {
console.time('batchGetSubs')
iteration = 1;
let dataArray = []; promises = [];
// LOOP THROUGH FILES, THEN GET TENANTS BY SUB
for (i = iteration; i < totalIterations; i++) {
let msIds = await loopAndDump(iteration);
// LOOP THROUGH TENANTIDS AND GET SUBSCRIPTIONS
msIds.map(async item => {
let newRecord = await getSubsByTenantId(item);
promises.push(await newRecord);
});
}
Promise.all([promises]).then(() => { // FIXME: WHY IS THIS NOT WAITING FOR ALL RESPONSES?
console.log(p1SubscriptionArray),
console.timeEnd('batchGetSubs')
});
}
async function getSubsByTenantId(msTenantId) {
let newRecord; let subscriptionArray = [];
let bearerToken = p1BearerToken;
let totalSubs = 0;
const subIdConfig = {
method: 'get',
url: ``,
headers: { 'Authorization': bearerToken }
}
await delay();
await axios(subIdConfig)
.then(async res => {
console.log('AXIOS RESPONSE', res.data);
if (res.data.items) {
let subItems = res.data.items;
console.log('^^^^^^^^^^^^^^^^^^', res.data.items)
// LOOP THROUGH AND ADD TO SUBSCRIPTION ARRAY
subItems.map(async subscription => {
if (subscription.friendlyName) {
totalSubs++;
subscriptionArray.push(subscription.friendlyName);
}
});
newRecord = { "tenantId": msTenantId, "totalSubs": totalSubs, "subscriptionFriendlyName": subscriptionArray };
} else {
// NO SUBS
newRecord = { "tenantId": msTenantId, "totalSubs": totalSubs, "subscriptionFriendlyName": ['NONE'] };
let statusCode, errorMessage;
if (error && error.response === undefined) { // GETTING STATUS -4039 or -4077 INSTEAD OF 429 WHEN CHECKING SUBS. FORCE A RESEND.
if (error.errno && error.errno === -4039 || error.errno && error.errno === -4077) statusCode = 429; errorMessage = error.code;
} else {
statusCode = error.response.status;
errorMessage = error.response.statusText;
}
console.error('ERROR:: SUBIDCONFIG SECTION THROWING ERROR: ', statusCode, portal, errorMessage);
// SORT NON-200 CALLS BASED ON STATUS CODE
switch (statusCode) {
case 403:
status403.push('subs', newRecord);
break;
case 404:
status404.push('subs', newRecord);
erroring = true;
break;
case 429:
status429.push('subs', newRecord);
erroring = true;
break;
default:
statusOther.push('subs', newRecord)
erroring = true;
break;
}
}
})
.catch(err => {
newRecord = { "tenantId": msTenantId, "totalSubs": totalSubs, "subscriptionFriendlyName": ['NONE'] };
console.error('ERROR: REQUEST IN GETSUBSBYTENANTID(): ', err)
})
.then(res => {
console.log('DO WE HAVE ANY INFORMATION? ', newRecord);
p1SubscriptionArray.push(newRecord);
resolve();
});
}
解决方案
我只检查了您提出问题的第一个功能:
为什么不等待所有响应?
有几个原因:
promise
调用时数组仍然为空Promise.all
。这是因为您只在 apush
之后执行aawait
,因此这是push
异步发生的(阅读:稍后)。即使
promises
数组被填充,它也不会有 Promise 对象,而是解析值(即newRecord
值)即使
promises
本来是一组承诺,你也没有将该数组正确传递给Promise.all
:你将该数组包装在另一个数组中,然后该数组只有一个条目,并且该条目不是一个承诺,而是一个数组。
与您的问题无关,但是:
请养成明确声明所有变量的习惯。您没有为
iteration
,promises
或执行此操作i
。仅
.map
在您对返回值执行某些操作时使用。对于纯迭代使用.forEach
orfor
。在这种情况下,您可以使用返回值来扩展promises
数组。如果您打算调用
batchGetSubs
并需要知道所有操作何时完成,请确保它返回一个有用的承诺:returnPromise.all()
这是该功能的建议更正:
async function batchGetSubs(data, command) {
console.time('batchGetSubs')
let iteration = 1; // Declare!
let dataArray = [];
let promises = []; // declare
// declare i
for (let i = iteration; i < totalIterations; i++) {
let msIds = await loopAndDump(iteration);
// Use the return value of the map method. No need for async callback
promises.push(...msIds.map(item => {
// Get the promise, not the resolved value, as that will come too late:
return getSubsByTenantId(item);
}));
}
// promises is already an array; don't make it an array of arrays.
// And: return the resulting promise: it may be useful to the caller.
return Promise.all(promises).then(() => {
console.log(p1SubscriptionArray),
console.timeEnd('batchGetSubs')
});
}
推荐阅读
- javascript - jQuery插件方法返回对象而不是值
- javascript - 对 React setState 的多次更新导致重新渲染地狱和阻塞
- html - 图片不显示在html中
- javascript - 如何在完成表格后下载图像,但表格是使用 wordpress 上的插件完成的
- c++ - 标准库容器最简单、性能差的哈希类是什么?
- angular - 如何从Angular中的数组初始化路由?
- android - RecyclerView 流过屏幕
- spring-boot - Springboot Mockito:模拟服务方法返回null
- haskell - 如何在haskell中运行一个独立的程序
- javascript - 如何在节点 js 中使用 es6 创建枚举值?