【问题标题】:Promise with q framework and the callback pattern in Node.js?Promise 与 q 框架和 Node.js 中的回调模式?
【发布时间】:2013-02-05 09:10:21
【问题描述】:

如果您使用 Node.js 进行编程几天,即使 q framework 有据可查,也很难理解。但我喜欢了解它!

var Q  = require('q');
var fs = require('fs');

// Make the promise manually (returns a value or throws an error)
var read1 = fs.readFile(fname, enc, function (err, data) {
    if(err) throw err;

    return data;
});

// Convenient helper for node, equivalent to read1?
var read2 = Q.nfbind(fs.readFile);

// Uh?!
var read3 = function (fname, enc) {
    var deferred = Q.defer();

    fs.readFile(fname, enc, function (error, text) {
        if (error) {
            deferred.reject(new Error(error));
        } else {
            deferred.resolve(text);
        }

        return deferred.promise;
    });
};


// Execute
Q.fncall(read1).then(function (data) {}, function (err) {}).done();

read1read2read3 是否等效?每次函数的最后一个参数接受function (err, value)风格的回调时,我可以使用Q.nfbind吗?

【问题讨论】:

    标签: node.js asynchronous promise q


    【解决方案1】:

    您的示例中有一些错误。

    读取1

    这不是“手动做出承诺”,这只是进行正常的异步调用。在您的代码中,您立即调用readFile,因此read1 将是readFile 的返回值undefined。要获得类似于 read2read3 的行为,您需要执行以下操作:

    var read1 = function(fname, env, success, error){
      fs.readFile(fname, enc, function (err, data) {
        // Throwing here would just crash your application.
        if(err) error(err);
    
        // Returning from inside 'readFile' does nothing, instead you use a callback.
        else success(data);
      });
    };
    

    读取2

    // Not equivalent to read1 because of the notes above,
    // Equivalent to read3, with the fixes I mention below.
    var read2 = Q.nfbind(fs.readFile);
    

    读取3

    var read3 = function (fname, enc) {
        var deferred = Q.defer();
    
        fs.readFile(fname, enc, function (error, text) {
            if (error) {
                // 'error' is already an error object, you don't need 'new Error()'.
                deferred.reject(error);
            } else {
                deferred.resolve(text);
            }
    
            // HERE: Again returning a value from 'readFile' does not make sense.
            return deferred.promise;
        });
    
        // INSTEAD: Return here, so you can access the promise when you call 'read3'.
        return deferred.promise.
    };
    

    您确实可以在将回调作为最后一个参数的任何东西上使用nfbind。 在我的 cmets 中,read2read3 实现了相同的目标,即创建一个接受文件名和编码的函数,并返回一个 promise 对象。

    对于那些,你可以这样做:

    read2('file.txt', 'utf8').then(function (data) {}, function (err) {}).done();
    read3('file.txt', 'utf8').then(function (data) {}, function (err) {}).done();
    

    对于read1,你可以这样称呼它:

    read1('file.txt', 'utf8', function (data) {}, function (err) {});
    

    更新

    自从回答这个问题后,标准承诺已经发生了一些变化,如果您倾向于read3,我建议您执行以下操作:

    var read4 = function (fname, enc) {
        return Q.promise(function(resolve, reject){
            fs.readFile(fname, enc, function (error, text) {
                if (error) {
                    // 'error' is already an error object, you don't need 'new Error()'.
                    reject(error);
                } else {
                    resolve(text);
                }
            });
        });
    };
    

    这更符合标准 ES6 承诺和 bluebird,因此您可以更轻松地推进代码。使用read3中提到的方法还引入了同步抛出异常的可能性,而不是在promise链中捕获它们,这通常是不可取的。见the deferred antipattern

    【讨论】:

    • 可爱的答案。不要忘记.done() 的奖励积分! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-18
    • 1970-01-01
    • 2017-01-09
    相关资源
    最近更新 更多