0

Using BlueBird promises, I am trying to make getCredentials into a promise that will work as getCredentials.then(function() { do this and that } );. Not sure what I am doing wrong, because when I resolve in writeToFile the promise is not counted as resolved/fullfilled.

function getPassword(user) {
    return new Promise(function(resolve, reject) {
    read({prompt: "Password: ", silent: true, replace: "*" }, function (er, pass) {
        rest.postJson(URL, payload(user, pass))
            .on('fail', httpFail)
            .on('error', conError)
            .on('success', writeToFile);
    });
    });
}

function getCredentials() {
    return new Promise(function(resolve, reject) {
    read({prompt: "Username: "}, function (er, user) {
        getPassword(user);
    });
    });
}

function writeToFile(data, response) {
     return new Promise(function(resolve, reject) {
    tokenFile = 'gulp/util/token-file.json'
    token = {
        id: data.access.token.id,
        expires: data.access.token.expires
    }
    token = JSON.stringify(token);
    fs.writeFile(tokenFile, token, function(err) {
        if (err) throw err;
        console.log("Token was successfully retrieved and written to " .cyan +
            tokenFile .cyan + "." .cyan);
    resolve();
    });
     });
}

module.exports = getCredentials;
Cœur
  • 37,241
  • 25
  • 195
  • 267
dman
  • 10,406
  • 18
  • 102
  • 201
  • 1
    Why are you always ignoring `er`rors? Use proper [promisification](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification) instead of the `Promise` constructor. – Bergi Mar 10 '15 at 14:53
  • 1
    What are `httpFail` and `conError`? – Bergi Mar 10 '15 at 14:58
  • Those are call back functions. I tried using promisify but didn't have success...I thought was because maybe some of the functions didn't fall exactly to node standards. – dman Mar 10 '15 at 17:18

2 Answers2

1

getCredentials() and getPassword() are not resolving their promises when they are complete. They never get resolved.

I assume from the code that you also want to chain the getPassword promise with the writeToFile promise so getPassword doesn't resolve until writeToFile does.

That could look something like this:

function getPassword(user) {
    return new Promise(function(resolve, reject) {
        read({prompt: "Password: ", silent: true, replace: "*" }, function (er, pass) {
            rest.postJson(URL, payload(user, pass))
                .on('fail', httpFail)
                .on('error', conError)
                .on('success', function(data, response) {
                    writeToFile(data, response).then(resolve);
                });
        });
    });
}

You probably also want to implement error handling.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

Not sure what I am doing wrong, because when I resolve in writeToFile the promise is not counted as resolved/fullfilled

Well, the promise that you did return from writeToFile is fulfilled.
But the promises that are returned from getPassword or getCredentials never are - you are not calling their resolve functions. The Promise constructor does not magically know about the asynchronous callbacks that were used inside of it, or that there were will be promises created in them.

You cannot return anything from an asynchronous callback, your only way to signal results from there is by calling another (callback) function. Inside of the Promise constructor's resolver, that would be the resolve and reject callbacks.

You might want to have a look a my rules for promise development. We almost never use the Promise constructor, only to promisify at the lowest possible level. In your case, that would be

function readAsync(options) {
    return new Promise(function(resolve, reject) {
        read(options, function (err, pass) {
            if (err) reject(err);
            else resolve(pass);
        }
    });
}
function postAsync(url, payload) {
    return new Promise(function(resolve, reject) {
        rest.postJson(url, payload)
        .on('fail', reject)
        .on('error', reject)
        .on('success', resolve);
    });
}

though with Bluebird we can simplify the first to

var readAsync = Promise.promisify(read);

and similar use

var writeFileAsync = Promise.promisify(fs.writeFile, fs);

Now that we have those promise-returning functions, we can apply the rest of the rules and compose them together, without needing to use the Promise constructor any more:

function getPassword(user) {
    return readAsync({prompt: "Password: ", silent: true, replace: "*" })
    .then(function(pass) {
        return postAsync(URL, payload(user, pass))
    });
}

function getCredentials() {
    return readAsync({prompt: "Username: "}).then(getPassword);
}

function writeToFile(data, response) {
    var tokenFile = 'gulp/util/token-file.json';
    var token = JSON.stringify({
        id: data.access.token.id,
        expires: data.access.token.expires
    });
    return writeFileAsync(tokenFile, token).then(function() {
        console.log("Token was successfully retrieved and written to " .cyan +
                    tokenFile .cyan + "." .cyan);
    });
}

module.exports = getCredentials;
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375