【问题标题】:Promise.allSettled stuck foreverPromise.allSettled 永远卡住
【发布时间】:2021-03-21 14:52:46
【问题描述】:

我使用Promise.allSettled 批量获取网站。如果我将网站列表的大小限制为10,它可以正常工作,但是一旦我将其增加到1000,它就会卡住。

这很奇怪,从来没有发生在我身上。我已经等了三天,直到脚本完成,但它仍然停留在第一个 1000 项目上。

const rp = require('request-promise');
const lineReader = require('line-by-line');

const reader = new lineReader("./all.json");

let lines = [];
const limit = 1000;

let successCount = 0;

reader.on('line', async (line) => {
    line = JSON.parse(line);

    lines.push(line);

    if (lines.length === limit) {
        reader.pause();

        let promises = [];

        for (const line of lines) {
            promises.push(rp(line.website))
        }
    
        await Promise.allSettled(promises);

        successCount++
        console.log(`Success Count is ${successCount}`);

        lines = [];

        reader.resume();
    }
});

data.json 文件有以下格式的网站列表,

{ website: "https://www.google.com" }
{ website: "https://www.bing.com" }
{ website: "https://www.microsoft.com" }

您可以通过将 { website: "https://www.google.com" } 之类的行复制 2000 次来重现该行为。

【问题讨论】:

  • @trincot 不。这是 1000 个并发请求,它永远卡住了。这些请求适用于不同的网站,但我发现您可以通过复制 {website: "https://www.google.com"} 2000 次之类的行来重现该行为
  • 以下也会永远挂起吗?您的代码中有不止一个 Promise.allSettled Promise.allSettled(Array.from({length: 2000}, () => 'https://www.google.com').map(x => fetch(x))).then(() => console.log('done'))
  • @geoffrey Yours 有效,但我不知道我的代码有什么问题。我现在缩短了代码并编辑了问题。你觉得这有什么问题吗?
  • @geoffrey 我使用逐行包来读取通行并推送到 Lines 数组。一旦 Lines 数组达到限制,我指定逐行读取器暂停,然后循环遍历 Lines 数组上的每个项目并执行获取请求,然后推送到 promises 数组,然后我为包含的数组调用 Promise.allSettled承诺。
  • @Bergi 似乎 lib 中有一些错误。发现另一个问题。 stackoverflow.com/q/56320940/14659574

标签: javascript


【解决方案1】:

解决方案是用一个在一段时间后超时的承诺来结束我的承诺。

这是提供超时承诺能力的函数,

const withTimeout = (millis, promise) => {
    const timeout = new Promise((resolve, reject) =>
        setTimeout(
            () => reject(`Timed out after ${millis} ms.`),
            millis));
    return Promise.race([
        promise,
        timeout
    ]);
};

你可以像下面这样使用它,

await Promise.allSettled([
   withTimeout(5000, rp("https://www.google.com"),
   withTimeout(5000, rp("https://www.bing.com"),
]));

我知道您可以在 request-promise 选项中指定超时,但由于某种原因它对我不起作用,但我在添加它时注意到了某些改进。

【讨论】:

  • 完美答案。
猜你喜欢
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多