0

I am learning node and promises. I've simplified my problem and sharing my code below.

I have three modules: app.js, modLanguage.js and model.js

app.js:

var l = require('../test/modLanguage.js');

var params = [{
   p0: 'johnDoe',
   p1: '12345',
   p2: 0
}];

var lang = l.call(params);
console.log("Needs to run last: " + lang.language);

modLanguage.js:

var call = function(params) {
    var langQuery = require('../test/model.js');
    var userLang = createLanguage();

    userLang.setLanguage('FRENCH');
    console.log("This needs to run first - setting lang French before DB dip: " + userLang.language);

    var myData = langQuery.getLanguage(params)
        // My DB dip
        .then(function(data) {
            var data = JSON.parse(JSON.stringify(data[0]));
            userLang.setLanguage(data[0].Language);
            console.log("Needs to run second - DB dip brought language ENG: " + userLang.language);
            return userLang;
        })
        .catch(function(err) {
            console.log('error');
        });
    return userLang;
}
module.exports.call = call;


function createLanguage() {
    return {
        language: this.language,
        setLanguage: function(language) {
            this.language = language;
            return this.language;
        }
    }
}

model.js is a simple module which uses params, runs a stored procedure and brings back data by returning a promise.

I want to block the running of code at app.js until the object is initialized from the data returned against Database dip. However, as is, the console.log shows:

This needs to run first - setting lang French before DB dip: FRENCH

Needs to run last: FRENCH

Needs to run second - DB dip brought language ENG: ENG

What I want to achieve is obviously:

This needs to run first - setting lang French before DB dip: FRENCH

Needs to run second - DB dip brought language ENG: ENG

Needs to run last: ENG

Please, advice the changes I need to make to achieve that?

1
  • 2
    you need to return a promise from call if you want to wait on it in app.js ... and use .then in app.js because at the moment you are not using Promises correctly Commented Sep 29, 2017 at 3:19

2 Answers 2

1

Here are the lines that need to change, and why.

// Instead of assigning this promise to a variable that you never 
// even use, just return the promise to the caller, so caller can wait
// for a result to actually be there.

return langQuery.getLanguage(params)

// Returning userLang will cause your app to process userLang
// before you've attached the proper language to it. Don't return
// it. Instead, return the promise that tells you userLang will
// be ready, as described above.

return userLang; // delete this line


// Now that the promise is returned instead of an incomplete
// object, we can wait for the promise to resolve before logging.

var lang = l.call(params).then(lang => 
  console.log("Needs to run last: " + lang.language)
);


Here is a working snippet to demonstrate.

As a sidenote, var is essentially deprecated in favor of let, which behaves almost exactly the same, except for a fix for some gotcha! scoping behavior.

I think using const is better than let for every assignment statement in this example, but will use let here on your behalf, since it's a much smaller step away from using var.

If you are working in a codebase that forces you to use var, then make sure that you research the differences between var/let, otherwise just quit using var and your life will be nicer for it.

/** some mock-ups to make the example run in a snippet **/

const module = {exports: {}}

let modelMock = {
    getLanguage(params){
        return Promise.resolve([[{
            Language: 'en-us'
        }]])
    }
}

function require (path) {
    if (path === '../test/model.js')
        return modelMock;
    if (path === '../test/modLanguage.js')
        return module.exports;
}

/********* log to output pre instead of console *********/

console.log = (...args) =>
    [...args].forEach(arg =>
        document.querySelector('pre').innerText += '\n' + arg
  );

/******************* modLanguage.js *********************/

let call = function(params) {
    let langQuery = require('../test/model.js');
    let userLang = createLanguage();

    userLang.setLanguage('FRENCH');
    console.log(
        'This needs to run first - setting lang French before DB dip: '
        + userLang.language
     );

    return langQuery.getLanguage(params)
        // My DB dip
        .then(function(data) {
            // JSON.parse is known to throw. We should always wrap it
            // in a try catch block and decide how to deal with the error.
            // In this case, I'm just rethrowing with clearer message.
            try { data = JSON.parse(JSON.stringify(data[0])); }
            catch(e) { 
                e. message = 
                  'langQuery.getLanguage could not parse provided data';
                throw e;
            }
            
            userLang.setLanguage(data[0].Language);
            
            console.log(
              'Needs to run second - DB dip brought language ENG: '
              + userLang.language
            );
            
            return userLang;
        })
        .catch(function(err) {
            console.error('error');
        });
}


module.exports.call = call;

function createLanguage() {
    return {
        language: this.language,
        setLanguage: function(language) {
            this.language = language;
            return this.language;
        }
    }
}

/************************ app.js ************************/

let l = require('../test/modLanguage.js');

let params = [{
    p0: 'johnDoe',
    p1: '12345',
    p2: 0
}];

l.call(params).then(lang => 
    console.log("Needs to run last: " + lang.language)
);
<pre></pre>

Sign up to request clarification or add additional context in comments.

3 Comments

Hello, I made the changes you've suggested however the last bit never gets called. I tried to add the latest code but it is too long as a comment
Not sure where your problem is then. I added a runnable snippet of your example that behaves as expected.
Thank you! It works just as I expected and the nuance about let/var/const is the icing on the cake - gives me a direction on what to research/work on next. Using your provided code, I'll also re-trace my errors.
0

You could return a promise from call. Instead of setting lang directly with the return value do l.call(...).then(...); and do your last call and set lang inside the callback.

1 Comment

I tried that before posting as well... But I am lost on what to do/change on app.js. Could you please give an example on the code I provided?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.