async/await 使用 Limiter 发送请求

async/await with Limiter for sending requests

我正在尝试限制发送给 API 的请求数量。

我正在使用 Limiter,它的工作方式和我需要的一样,唯一的问题是我找不到将它与 await 一起使用的方法(在呈现我的页面之前我需要所有响应)

有人可以帮助我吗?

顺便说一句,日志 returns 一个布尔值。

const RateLimiter = require('limiter').RateLimiter;

const limiter = new RateLimiter(50, 5000)

for (let i = 0; i < arrayOfOrders.length; i++) {
    const response = limiter.removeTokens(1, async (err, remainingRequests) => {
        console.log('request')
        return await CoreServices.load('updateOrder', {
            "OrderNumber": arrayOfOrders[i],
            "WorkFlowID": status
        })
    })
    console.log('response', response)
}

console.log('needs to log after all the request');

这是登录:

response true
response true
response false
needs to log after all the request
request
request
request
...

承诺 .removeTokens 会有所帮助,看看这段代码是否有效

const RateLimiter = require('limiter').RateLimiter;

const limiter = new RateLimiter(50, 5000);

const tokenPromise = n => new Promise((resolve, reject) => {
    limiter.removeTokens(n, (err, remainingRequests) => {
        if (err) {
            reject(err);
        } else {
            resolve(remainingRequests);
        }
    });
});
(async() => { // this line required only if this code is top level, otherwise use in an `async function`
    const results = await Promise.all(arrayOfOrders.map(async (order) => {
        await tokenPromise(1);
        console.log('request');
        return CoreServices.load('updateOrder', {
            "OrderNumber": order,
            "WorkFlowID": status
        });
    }));
    console.log('needs to log after all the request');
})(); // this line required only if this code is top level, otherwise use in an `async function`

说明

首先:

const tokenPromise = n => new Promise((resolve, reject) => {
    limiter.removeTokens(n, (err, remainingRequests) => {
        if (err) {
            reject(err);
        } else {
            resolve(remainingRequests);
        }
    });
});

promisifies limiter.removeTokens 在 async/await 中使用 - 在 nodejs 中你可以使用内置的 promisifier,但是最近我有太多失败的例子 - 所以手动 promisification(我我在这里编造了很多单词!)同样有效

现在代码很简单 - 您可以使用 arrayOfOrders.map 而不是 for 循环来创建一个承诺数组,所有 运行 都在速率限制允许的范围内并行,(速率限制在回调中完成)

await Promise.all(... 将等到所有 CoreServices.load 完成(或者一个失败 - 如果需要,您可以使用 await Promise.allSettled(...

地图回调中的代码被标记为async所以:

await tokenPromise(1);

将等到调用 removeTokens 回调 - 然后请求

return CoreServices.load

制作

注意,这最初是 return await CoreServices.load 但 await 是多余的,因为异步函数中的 return await somepromisereturn somepromise 相同 - 所以,也要调整你的代码