我正在用node/mongo/mongoose生成一堆数据,并希望为每个项调用反向地理代码API,但由于来自外部API的请求太多,我要用到429。 我尝试使用lodash.delay()
在内部强制等待每个请求,但没有成功。 理想情况下,我还希望分叉子进程,以免阻塞脚本/进程。 (虽然这是为了开发目的,所以我不在乎)。
messageSchema.pre("insertMany", async function save(next, docs) {
docs.map(async (doc) => {
[err, response] = await to(
delay(
reverseGeocode(
doc.location.coordinates[0],
doc.location.coordinates[1]
),
3000
)
);
if (err) {
throw new Error(err);
}
});
console.log(this);
});
由于NodeJS
具有本机异步承诺支持,因此不需要“分叉”进程。
最好的解决方案实际上是在您的代码中添加延迟以匹配限制。 假设这太麻烦了,而且这仅仅是为了开发目的,这里是一个快速的蛮力示例:
请注意,等待承诺不会像同步代码那样阻塞进程。
async function getGeoCode(doc) {
return reverseGeocode(
doc.location.coordinates[0],
doc.location.coordinates[1]
)
}
const randomSleep = [1000, 2000, 3000, 4000, 5000, 6000];
messageSchema.pre("insertMany", async function save(next, docs) {
let sleep = false;
docs.map(async (doc) => {
while (sleep) {
const randomSleep = randomSleep[Math.floor(Math.random() * randomSleep.length)];
await new Promise(function (resolve) {
setTimeout(resolve, 2000 + randomSleep)
});
}
let [err, response] = await getGeoCode(doc);
if (err) {
if (err.statusCode !== 429) {
throw new Error(err);
}
sleep = true;
while (err && err.statusCode === 429) {
const randomSleep = randomSleep[Math.floor(Math.random() * randomSleep.length)];
await new Promise(function (resolve) {
setTimeout(resolve, 2000 + randomSleep)
});
[err, response] = await getGeoCode(doc);
}
sleep = false;
}
});
console.log(this);
});
我使用这个库来限制请求。 您只需告诉它API的速率限制是多少,您就可以任意快速地调用它,它将自动地为您间隔一段时间的请求。
如果您不想要另一个依赖项,那么为了使您的解决方案工作,您需要使用for
循环。 map
将始终尽可能快地执行。
const wait = (time) => {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
messageSchema.pre("insertMany", async function(next, docs) {
for(let i in docs) {
const doc = docs[i];
await wait(3000); // milliseconds to space requests out by.
const [err, response] = await to(
// You probably need to adjust this since you didn't tell us
// what your reverse geocode function actually returns.
reverseGeocode(
doc.location.coordinates[0],
doc.location.coordinates[1]
)
);
if (err) {
throw new Error(err);
}
}
console.log(this);
});
这可能有点错误,因为我不确定to
和reverseGeocode
函数实际做什么。 如果你给我更多关于你的代码如何工作的信息,我可以给你一个确切的答案。 reverseGeocode
只是构建请求参数并使用to
发出请求吗? 或者reverseGeocode
是异步的?