【问题标题】:Why is promise-limit not working in Nodejs?为什么 promise-limit 在 Nodejs 中不起作用?
【发布时间】:2021-01-16 08:42:27
【问题描述】:

我有大量图像要下载。我正在使用 request-promise 包从他们的 URL 下载图像。由于有大量图像,服务器过载,下载会挂起或损坏,所以我决定使用promise-limit 库来设置并发限制。这是我的代码:


const fs = require('fs');
const request = require('request-promise');
const promiseLimit = require('promise-limit');

var limit = promiseLimit(30);

async function download(data) {
    console.log(data);

    return Promise.all(data.map( (obj) => {
        return limit(() => downloadRequest(obj))
    })).then(() => {
        console.log("All images downloaded.")
    })

function downloadRequest(obj) {
    var img = obj.dest;
    var url = obj.url;
    var req = request(url);
    req.pipe(fs.createWriteStream(img));
}

我完全按照 github 页面中给出的方式复制了示例,但是该方法返回时没有满足 Promise.all()。我不明白我做错了什么,我认为 Promise.all() 肯定会等到它解决所有承诺。

在后端,这个调用被用作

...
.then((data) => {
        return downloader.download(data);
    })
    .then(() => {
        var filename = "Sample.pdf";
// Pages.json is written early in the chain, contains URL and corresponding image paths
        return generator.generate('./Pages.json', filename); 
    });

这是否意味着 NodeJS 已经在尝试从 pages.json 生成文件?如何让这部分代码同步下载?

【问题讨论】:

标签: javascript node.js concurrency promise limit


【解决方案1】:

您的函数downloadRequest() 没有返回承诺。它必须返回一个与包含中的异步操作相关联的承诺,以便在异步操作完成时解决承诺,或者在异步操作出现错误时拒绝承诺。只有这样,limit() 包才能正常工作。

由于您使用的是流并在downloadRequest() 中进行管道传输,因此您必须手动构造一个promise,然后监视流中的各种事件以了解它何时完成或出现错误,以便您解决或拒绝那个承诺。

这是一个如何让downloadRequest() 正确返回承诺的想法:

function downloadRequest(obj) {
    return new Promise((resolve, reject) => {
        const img = obj.dest;
        const url = obj.url;
        const req = request(url);

        req.on('error', reject);

        const ws = fs.createWriteStream(img);
        ws.on('error', reject);
        req.pipe(ws).on('finish', resolve);
    });
}

而且,现在建议使用pipeline() 函数而不是.pipe(),因为它可以在错误情况下进行更彻底的清理,并且还有一个内置的promise 版本:

const { pipeline } = require('stream/promises');

function downloadRequest(obj) {
    return pipeline(request(obj.url), fs.createWriteStream(obj.dest));
}

附:如果您不知道,request() 库已被弃用,建议您不要再在新项目中使用它。有一个可供选择的替代库列表 here,所有这些库都具有内置的 Promise 支持。我查看了各种选择,尝试了几个,并决定在我的工作中使用got()

【讨论】:

  • 成功了,谢谢!我会尝试复制它并迁移到您提到的其他库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 2020-12-29
  • 2017-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多