【问题标题】:Utilising Nodejs Promises (Bluebird) during module loading and configuration在模块加载和配置期间使用 Nodejs Promises (Bluebird)
【发布时间】:2015-01-29 08:51:36
【问题描述】:

早安

我一直在搜索 S.O.在过去的几天里,我试图找到一个我理解/适用于我的情况的答案,现在承认失败,主要是因为我对 Promises (promise-n00b) 缺乏理解。因此,我基本上是在为下面发布的示例请求一些帮助。我认为这可以很好地解释我在做什么,但如果不是,我正在尝试:

  • 将一些同步配置应用到服务器
  • 加载一个 Logger 模块并将它的一个新实例实例化为 logger,然后运行一些必要的检查(例如,我们是否有一个日志文件?),然后返回一个指示它已成功加载(布尔值或logger 对象本身)
  • 然后将该记录器传递给实用程序(他们需要它来记录)
  • 最后调用npm startnpm test运行的脚本传入的回调

显然,现实世界中还有很多事情要做,但我试图将代码提炼成我没有得到的部分,即 Promise 链。

最后,作为一个从不费力地理解回调的长期用户(大脑可能必须以不同的方式工作),你们中的任何人是否有任何可能引起灯泡时刻的智慧珍珠?

在此先感谢您,是的,我知道这段代码不能/不会工作 ;-)

代码如下:

server.js

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs-extra'));

var boss = {
start: function(callback) {
    var p = new Promise.try(function() {
        console.log('start');
    })
    .then(boss.applyConfig)
    .then(boss.startLogger)
    .then(function(lggr) {
        console.log('logger setup complete: ' + lggr);
        boss.logger = lggr;
        return lggr;
    })
    .then(boss.loadUtils)
    .finally(function() {
        if (callback) callback();
    })
    .catch(function(err) {
        console.log.call(null, '\033[31m' + err.stack + ' \033[39m');
    });
},
applyConfig: function() {
    console.log('applying config');
    return 'config';
},
startLogger: function() {
    console.log('starting logger');
    var Logger = require('./Logger')(fs, Promise);
    var logger = new Logger();
    return new Promise(function(resolve, reject) {
        var result = logger.init();

        if (result) {
            resolve(logger);
        }
        else {
            reject(logger);
        }
    });
},
loadUtils: function(logger) {
    console.log('loading utils with ' + logger);
    boss.logger.log('loading utils with ' + logger);
    return 'utils';
}
};

boss.start(function(){
   console.log('done');
});

Logger.js

module.exports = function(fs, Promise) {

var Logger = function(options) {
    this.filePath = (options && options.filePath) ? options.filePath : __dirname + '/../log/';
    this.filename = (options && options.filename) ? options.filename : 'all.log';
};

Logger.prototype.init = function() {
    var logger = this;
    console.log('logger.init');
    return new Promise(function(resolve) {
        new Promise.resolve(logger.checkForLogFile()).then(function(exs) {
            console.log('exs', exs);
            return exs;
        });
    })
};

Logger.prototype.log = function(msg) {
    // requires that the log file exists and that we have a stream to it (create stream function removed)
    console.log.call(null, '\033[36mLogging: ' + msg + ' \033[39m');
};

Logger.prototype.checkForLogFile = function() {
    var logger = this;
    fs.existsAsync(logger.filePath + logger.filename).then(function (exists) {
        console.log('exists', exists);
        return exists;
    });
};

return Logger;
};

【问题讨论】:

  • 注意 [延迟反模式](stackoverflow.com/questions/23803743/what-is-the-deferred-antipattern-and-how-do-i-avoid-it) - 你不需要到处都是new Promise - 只需返回承诺并使用then 进行链接。此外-在checkForLogFile中,您没有返回承诺(您在fs.existsAsync之前缺少return-更糟糕的是-existsAsync不适用于承诺,因为exists被破坏了-如果您必须使用它使用 statAsync 代替 - 否则避免使用它,因为它容易受到竞争条件的影响(文件是在存在检查和下一个命令之间创建的?)
  • 另外 - 返回 p 而不是在您承诺的方法中接受回调(如 start
  • 感谢您对 existsAsync Benjamin 的提醒 - 这解释了很多!现在正在浏览你的其他 cmets。
  • 关于你的第二条评论(关于在开始时返回 p),我故意不想这样做,因为我不希望调用脚本必须理解 Promises - 你认为这是一个回调的可接受用例还是我完全搞错了?
  • 好的,阅读您的其他 cmets,仍然不明白 - 当您说“简单地返回承诺”时,实际实现中这是什么(我认为这就是我正在做的)。

标签: node.js promise require bluebird node-modules


【解决方案1】:

首先 - 感谢 Benjamin :) 其次,令人惊讶的是,所有这些现在都可以在发布到 S.O. 的 30 分钟内完成。经过几天的努力;-)

所以是的 - 金色外卖金块是 KISS!

以下代码现在可以正常工作并以正确的顺序登录,如下所示:

start
applying config
starting logger
logger.init
statObj { dev: 2067,
  mode: 33204,
  ...
  ctime: Thu Nov 27 2014 11:40:34 GMT+0000 (GMT) }
exists true
logger setup complete: [object Object]
loading utils with [object Object]
Logging: loading utils with [object Object] 
done

server.js

var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs-extra'));

var boss = {
start: function(callback) {
    var p = new Promise.try(function() {
        console.log('start');
    })
    .then(boss.applyConfig)
    .then(boss.startLogger)
    .then(function(lggr) {
        console.log('logger setup complete: ' + lggr);
        boss.logger = lggr;
        return lggr;
    })
    .then(boss.loadUtils)
    .finally(function() {
        if (callback) callback();
    })
    .catch(function(err) {
        console.log.call(null, '\033[31m' + err.stack + ' \033[39m');
    });
},
applyConfig: function() {
    console.log('applying config');
    return 'config';
},
startLogger: function() {
    console.log('starting logger');
    var Logger = require('./Logger')(fs, Promise);
    var logger = new Logger();
    return logger.init();
},
loadUtils: function(logger) {
    console.log('loading utils with ' + logger);
    boss.logger.log('loading utils with ' + logger);
    return 'utils';
}
};

boss.start(function(){
   console.log('done');
});

Logger.js

module.exports = function(fs, Promise) {

var Logger = function(options) {
    this.filePath = (options && options.filePath) ? options.filePath : __dirname + '/../log/';
    this.filename = (options && options.filename) ? options.filename : 'all.log';
};

Logger.prototype.init = function() {
    var logger = this;
    console.log('logger.init');
    return logger.checkForLogFile().then(function(statObj) {
        var exists = (typeof statObj === 'object');
        console.log('exists', exists);
        return logger;
    });
};

Logger.prototype.log = function(msg) {
    // requires that the log file exists and that we have a stream to it (create stream function removed)
    console.log.call(null, '\033[36mLogging: ' + msg + ' \033[39m');
};

Logger.prototype.checkForLogFile = function() {
    var logger = this;
    return fs.statAsync(logger.filePath + logger.filename).then(function (statObj) {
        console.log('statObj', statObj);
        return statObj;
    });
};

return Logger;
};

【讨论】:

    猜你喜欢
    • 2016-09-25
    • 2017-04-03
    • 2016-09-24
    • 1970-01-01
    • 2014-08-20
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 2015-04-17
    相关资源
    最近更新 更多