Reputation: 65
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?
Upvotes: 0
Views: 61
Reputation: 1451
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>
Upvotes: 1
Reputation: 13940
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.
Upvotes: 0