0

I've been having trouble learning callbacks and promises coming from a synchronous programming language. I've been trying to get the result of the .env file, so then I can use it in my application but instead console.log(envdata) returns:

Promise {
  _bitField: 0,
  _fulfillmentHandler0: undefined,
  _rejectionHandler0: undefined,
  _progressHandler0: undefined,
  _promise0: undefined,
  _receiver0: undefined,
  _settledValue: undefined
}

In my console. How do I instead get the correct results from the file?

Here is my current code.

'use strict';

var envdata = {};
var path = require('path');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));

module.exports = function(app, options) {

    return new Promise(function(resolve, reject){
            envdata = getenvdata(options.basedir + path.sep + ".env");
            console.log(envdata); //need this to be the data
            app.envdata = envdata;
            resolve(app);
    });

    function getenvdata(path){
        return fs.readFileAsync(path, 'utf8')
        .then(function(data){
            data.split("\n").forEach(function(keyvalue) {
                var array = keyvalue.split('=');
                array[1] && (data[array[0]] = array[1]);
            });
            return data;
        });
    }
}
mateos
  • 1,405
  • 1
  • 17
  • 26

2 Answers2

1

The getenvdata is returning a promise so you need to use then function to collect your result like this

return new Promise(function(resolve, reject){
            getenvdata(options.basedir + path.sep + ".env").then(function(envdata){
            console.log(envdata); //need this to be the data
            app.envdata = envdata;
            resolve(app);
         })
    });
Prakash Sharma
  • 15,542
  • 6
  • 30
  • 37
1

To read the value of a promise you must attach yourself to the promise chain (i.e., you must register an event handler). This is done through .then() and the other Promise methods, as already noted.

I have are some remarks about your code though.

  • First off, don't use new Promise() unless you are promisfying a non-promise asynchronous function, i.e. one that relies on a callback. This is not the case here, so new Promise() should be avoided (this is called the Explicit Promise Construction Anipattern). readFileAsync already returns a promise, just keep using that one.
  • Promisifying functions yourself is itself something you should avoid in favor of utility functions like Bluebird's promisifyAll or node's util.promisify.
  • fs is a core module, you don't really need to require it.
  • The process of reading a file, splitting it into lines and then into keys and values can be implemented as a map-reduce operation, which Bluebird actually has neat helpers for.
  • Last but not least, look into async/avait.

Consider this alternative take:

'use strict';

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

module.exports = function(app, options) {
    return fs.readFileAsync(path.join(options.basedir, ".env"), 'utf8')
        .then(data => data.split("\n"))
        .map(line => line.split('='))
        .filter(keyval => keyval[1] > '')
        .reduce((obj, keyval) => { obj[keyval[0]] = keyval[1]; return obj;}, {});
    });
}

The last step creates a key-value object from the file entries. An alternative way of writing this in ES6 can be seen over here.

usage

var readEnvAsync = require('readEnvAsync');

readEnvAsync().then(env => {
    // ...
});
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Interesting regarding the chaining of utility functions, I've used it in my code. Thanks for the extra info. I understand promises a lot better now. – mateos Oct 08 '17 at 10:24
  • They can come in handy, one of the really nice features of Bluebird. – Tomalak Oct 08 '17 at 10:30