2014-12-01 2 views
1

Утро ВсеИспользование обещаний Nodejs (Bluebird) при загрузке и настройке модуля

Я прочесывал S.O. за последние пару дней, пытаясь найти ответ, который я понял/применил к моей ситуации, и теперь допустил поражение, в первую очередь из-за моего отсутствия понимания вокруг Promises (prom-n00b). Поэтому я в основном высказываю просьбу о помощи в моем примере, опубликованном ниже. Я думаю, что это довольно поясняющий, что я делаю, но в случае, если это не так, я пытаюсь:

  • Нанесите синхронные конфигурации на сервер
  • Грузоподьемности Logger модуль и экземпляр нового экземпляра из него как регистратор, а затем выполнить некоторые необходимые проверки (например, у нас есть файл журнала?) перед возвратом индикатора, чтобы сказать, что он загружен успешно (либо логический, либо сам журнал)
  • Затем передайте этот регистратор на utils (они нуждаются в нем для регистрации)
  • Наконец, вызовите обратный вызов, пройденный сценариями, запущенными npm start и npm 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; 
}; 
+1

Остерегаться для [отложенного анти-шаблона] (st ackoverflow.com/questions/23803743/what-is-the-deferred-antipattern-and-how-do-i-avoid-it) - вам не нужно «новое обещание» во всем - просто верните обещания и используйте 'then 'для цепочки. Более того - в 'checkForLogFile' вы не возвращаете обещание (вам не хватает' return' перед вашим 'fs.existsAsync' - хуже - 'existAsync' не работает с обещаниями, так как' exists' нарушен - если вы должны использовать его вместо 'statAsync' вместо этого, иначе избегайте его, так как он подвержен условиям гонки (файл создается между проверкой существования и следующая команда?) –

+1

Также - верните 'p', а не принимайте обратный вызов в ваших обещанных методах (например,' start') –

+0

Спасибо за хэдз-ап reAsAsync Benjamin - это многое объясняет! Просматривайте свои комментарии. –

ответ

0

Прежде всего - спасибо Бенджамину :) А во-вторых, как удивительно удивительно, что все это теперь будет работать в течение 30 минут после публикации на S.O. через пару дней до начала ;-)

Итак, да - золотой самолёт с самозахватом - 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; 
};