【问题标题】:Async Loop Not Honoring Async异步循环不尊重异步
【发布时间】:2021-06-01 04:18:32
【问题描述】:

我有点卡在异步函数上。

我要完成的工作 - 我正在创建一个批处理函数 (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.all 的缩进非常错误。
  • 我认为你可以把return放在Promise.all之前返回承诺,或者你可以await链式Promise.all(...).then(...)
  • promises 数组在传递给Promise#all 之后 被完全填充。

标签: javascript node.js loops asynchronous promise


【解决方案1】:

您同时执行 等待。 你做了一个承诺/然后等待/异步

async function getSubsByTenantId(msTenantId) {
    let newRecord; let subscriptionArray = [];
    let bearerToken = p1BearerToken;
    let totalSubs = 0;
    const subIdConfig = {
        method: 'get',
        url: ``,
        headers: { 'Authorization': bearerToken }
    }
    await delay();
    const r = await axios(subIdConfig)
    const reponse = r.data
    console.log(response)
}

如果你想尝试 catch 这样做:

async function getSubsByTenantId(msTenantId) {
    let newRecord; let subscriptionArray = [];
    let bearerToken = p1BearerToken;
    let totalSubs = 0;
    const subIdConfig = {
        method: 'get',
        url: ``,
        headers: { 'Authorization': bearerToken }
    }
    await delay();
    let r
    try {
      r = await axios(subIdConfig)
    } catch (error) {
     console.log(error)
    }
    const reponse = r.data
    console.log(response)
}

【讨论】:

  • 当您执行 await 时,您取消了承诺,因此您的 then 无法应用。
【解决方案2】:

我只检查了你提出问题的第一个函数:

为什么不等待所有响应?

有几个原因:

  1. 当您调用Promise.all 时,promise 数组仍然是空的。这是因为您只在await 之后执行push after,因此push 异步发生(阅读:稍后)。

  2. 即使promises 数组被填充,它也不会有承诺对象,而是解析值(即newRecord 值)

  3. 即使promises 是一个 promise 数组,您也没有将该数组正确传递给 Promise.all:您将该数组包装在另一个数组中,然后该数组只有一个条目,并且该条目不是承诺,但是一个数组。

与您的问题无关,但是:

  • 请养成明确声明所有变量的习惯。您没有为iterationpromisesi 执行此操作。

  • 仅在使用返回值做某事时使用.map。对于纯迭代使用.forEachfor。在这种情况下,您可以使用返回值来扩展promises 数组。

  • 如果你打算调用 batchGetSubs 并且需要知道什么时候完成,那么请确保它返回一个有用的承诺:return Promise.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')
    });
}

【讨论】:

  • 这是完美的,可以根据需要工作。我看到我嵌套的东西比我应该拥有的要多,并且声明 promises = msIds.map... 是我的救星。我在另一部分也声明了变量,应该提前提到这一点。谢谢你!
  • 很高兴听到。请注意我必须做出的改变。
猜你喜欢
  • 2018-10-17
  • 2018-09-18
  • 2020-03-07
  • 2018-09-15
  • 2017-05-02
  • 2017-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多