4

如果你用 Node.js 编程几天,即使有据可查的q 框架也很难理解。但我喜欢学习它!

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();

read1和等价read2的吗?每次函数的最后一个参数接受回调样式时,read3我可以使用吗?Q.nfbindfunction (err, value)

4

1 回答 1

11

您的示例中有一些错误。

读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在将回调作为最后一个参数的任何东西上使用。根据我的评论,read2实现read3相同的目标,即创建一个函数,该函数将采用文件名和编码,并返回一个 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 链中捕获它们的可能性,这通常是不可取的。请参阅延迟反模式

于 2013-02-20T17:43:30.293 回答