【问题标题】:Using promises with download module使用带有下载模块的 Promise
【发布时间】:2014-09-15 05:10:51
【问题描述】:

我正在使用 bluebird 进行承诺。

我试图承诺download module

这是我的实现:

Promise  = require('bluebird'),
download = require('download');

var methodNameToPromisify = ["download"];

function EventEmitterPromisifier(originalMethod) {
    // return a function
    return function promisified() {
        var args = [].slice.call(arguments);
        // Needed so that the original method can be called with the correct receiver
        var self = this;
        // which returns a promise
        return new Promise(function(resolve, reject) {
            // We call the originalMethod here because if it throws,
            // it will reject the returned promise with the thrown error
            var emitter = originalMethod.apply(self, args);

            emitter
                .on("response", function(data) {
                    resolve(data);
                })
                .on("data ", function(data) {
                    resolve(data);
                })
                .on("error", function(err) {
                    reject(err);
                })
                .on("close", function() {
                    resolve();
                });
        });
    };
};
download = { download: download };
Promise.promisifyAll(download, {
    filter: function(name) {
        return methodNameToPromisify.indexOf(name) > -1;
    },
    promisifier: EventEmitterPromisifier
});

然后使用它:

return download.downloadAsync(fileURL, copyTo, {});

我的问题是它没有下载所有文件(我有一个发送到这个函数的列表),我做错了什么?

【问题讨论】:

  • (a)download = { download: download }; 覆盖download = require('download'); 和(b).on("data ", ...) 中是否有该空间是故意的?
  • 我的错,我会努力解决的。

标签: node.js download promise bluebird


【解决方案1】:

发射器确实会发出 多个 数据事件,它接收到的每个块都有一个。但是,a 仅代表 一个 未来值,在您的情况下,您希望它是完整的响应。

resolve 应该只被调用一次,用传递的值履行承诺,然后解决。进一步的调用将无效 - 这就是为什么您只能获得列表的第一部分。

相反,您需要累积所有数据,当流结束时,您可以用所有数据来履行承诺。

var Promise  = require('bluebird'),
    download = require('download'),
    Buffer   = require('buffer'); // should be global anyway

exports = {
    downloadAsync: function promisifiedDownload() {
        var args = arguments, self = this;

        return new Promise(function(resolve, reject) {
            // We call the originalMethod here because if it throws,
            // it will reject the returned promise with the thrown error
            var emitter = download.apply(self, args);
            var buffers = [];

            emitter.on("data", function(data) {
                buffers.push(data);
            }).on("error", function(err) {
                reject(err);
            }).on("close", function() {
                resolve(Buffer.concat(buffers));
            });
        });
    };
};

请注意,当您只想承诺一个方法时,使用promisifyAll 是非常荒谬的。为简单起见,我省略了它

您还可以侦听传入的response 对象,并将data 侦听器直接附加到它。然后您可以使用end event 而不是close

【讨论】:

  • 虽然 Angular 文档中的示例完整地说明了它(如上),但大概.on("error", reject) 也可以吗?
  • @Bergi,我必须删除 require("buffer") 才能工作,谢谢!它使事情变得更加清晰。
  • 噢!我的意思是上面的“Bluebird”文档,而不是“Angular”
  • @agam360: 嗯,the docs 说“Buffer 类是全球性的,因此很少有人需要 require('buffer')”,但是我看不出有什么问题。
  • 我的参考只是Bluebird API,在.promisifyAll() option-promisifier部分找到“function EventEmitterPromisifier”。
猜你喜欢
  • 1970-01-01
  • 2021-05-14
  • 1970-01-01
  • 1970-01-01
  • 2023-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多