【问题标题】:node.js recursive download of chunked array with promisesnode.js 递归下载带有承诺的分块数组
【发布时间】:2017-06-25 11:43:49
【问题描述】:

我想下载很多图片(1000+),所以我将数组拆分成指定大小的块并一个接一个地下载。下载是基于承诺的,一旦一个块完成就解决。如果不使用块,一切正常,但使用此实现会发生以下情况:

console.log("Promise Recursive resolved", paths);

在下载递归函数完成后被调用,但它没有按预期解析,所以

console.log("Finished");

不会在 downloadAll 函数中调用。

function downloadAll(folder, full_size, images) {
    return new Promise(function (resolve, reject) {
        // Chunks of all images [ [1,2,3,4,5], [6,7,8,9,10], [...] ]
        let grouped_images = chunk(images, 5);

        downloadRecursive(folder, full_size, grouped_images, 1, []).then(function (e) {
            console.log("Finished");
            resolve(e);
        }).catch(function () {
            reject();
        });
    });
}


function downloadRecursive(folder, full_size, all, part, paths) {
    return new Promise(function (resolve, reject) {
        if(part > all.length){
            console.log("Promise Recursive resolved", paths);
            resolve(paths);
        }

        downloadImages(folder, all[part-1], full_size).then(function (e) {
            paths.push(e);
            return downloadRecursive(folder, full_size, all, part+1, paths);
        });
    });
}


function downloadImages(folder, images, full_size=true) {
    [...]

    return Promise.all(images.map(function (image) {
        [...]
        return doDownload(...);
    }));
}

function doDownload(url, path, full_size){
    returns promise
}

【问题讨论】:

  • 您可能会发现 Bluebird 的 Promise.map() 及其并发选项非常有用。它解决了这样的问题。如何同时运行不超过 N 的大量异步操作。
  • 像这样创建新的 Promise 是一种反模式。而不是执行“new Promise(...)...”然后从.then.catch 调用resolve/reject 放弃new Promise 并返回您的承诺链。见:jf.io/2016/10/09/…
  • 我同意上面的,问题可能是你在downloadRecursive中调用resolve后没有返回,所以它会额外运行downloadImages,可能会失败.
  • 在 downloadRecursive 中,除非(part > all.length),否则前提永远不会被解决或拒绝 - 所以,你会有“待定”的承诺
  • Promise.map() 看起来不错。我会调查的,谢谢。

标签: javascript node.js recursion ecmascript-6 promise


【解决方案1】:

与其使用递归调用,不如尝试使用array#reduce 像这样

function downloadAll(folder, full_size, images) {
    return chunk(images, 5)
    .reduce((promsie, chunk) => 
        promise.then((array) => 
            downloadImages(folder, chunk, full_size)
            .then(result => 
                array.concat(result)
            )
        ), Promise.resolve([])
    );
}


function downloadImages(folder, images, full_size=true) {
    [...]
    return Promise.all(images.map(function (image) {
        [...]
        return doDownload(...);
    }));
}

function doDownload(url, path, full_size){
    returns promise
}

【讨论】:

    【解决方案2】:

    您需要捕获并找出破坏链的错误,以便调试沿途发生的事情:

        downloadRecursive(folder, full_size, grouped_images, 1, []).then(function (result) {
            console.log("Finished");
            resolve(result);
        }).catch(function (error) {
            console.log("error in recursion:", error);
            reject(error);
        });
    

    如果您无法避免 1000 多张图像中出现几个错误,那么最坏的情况是,您可能需要在有问题的代码中添加一个 catch() 块,然后抑制错误并允许循环继续。

    【讨论】:

    • 链没有被错误破坏......事实上,downloadRecursive 中返回的 Promise 仅在 part > all.length 中被解析一次......并且递归无论如何都不会做任何链接!他可以(我认为)resolve(downloadRecursive(...)) 而不是return downloadRecursive - 但如果它甚至可以工作,那仍然是非常丑陋的代码......
    • 词链的多重定义
    • 认真的吗?语义?我说的是(不存在的)承诺链 - 最终的“解决方案”如何通过递归解决第一次调用中创建的 Promise?
    • 感谢您的解决方案:resolve(downloadRecursive(...)) 似乎有效,稍后我将进一步测试。你说这是丑陋的代码,你会如何用上面的reduce例子更好地实现整个过程?
    猜你喜欢
    • 2018-05-29
    • 1970-01-01
    • 2015-12-05
    • 2017-05-09
    • 2018-05-28
    • 1970-01-01
    • 2014-06-30
    • 2014-02-04
    • 1970-01-01
    相关资源
    最近更新 更多