I have a problem with returning array in Winjs promise and I don't have any idea what is wrong with my code. When i create a promise and do .done or .then my promise does nothing.
Code :
function getSth(array) {
return new WinJS.Promise(function () {
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\_db.sqlite';
var i = 0;
SQLite3JS.openAsync(dbPath)
.then(function (db) {
console.log('DB opened');
return db.eachAsync('SELECT * FROM sthh;', function (row) {
array[i++] = row.sth;
console.log('Get a ' + row.sth);
});
})
.then(function (db) {
console.log('close the db');
db.close();
}).then(function () {
return array;
});
return array;
})
}
And in other file I just do something like that :
var array = [];
var z = getSth(array).then(function () {
console.log("AAA");
for (var i = 0; i < array.length; console.log("#" + array[i]), i++);
});
I will be very gratefull for any suggestion.
I assume you don't want to return immediately and instead want to return the array once it is full of elements?
I think you want to write code that is more like this:
function getSth(array) {
var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\_db.sqlite';
var i = 0;
return SQLite3JS.openAsync(dbPath)
.then(function (db) {
console.log('DB opened');
return db.eachAsync('SELECT * FROM sthh;', function (row) {
array[i++] = row.sth;
console.log('Get a ' + row.sth);
});
})
.then(function (db) {
console.log('close the db');
db.close();
}).then(function () {
return array;
});
}
Related
I am trying to read some data from 2 different tables and parse a CSV file before rendering an ejs file.
I can get the data from both tables and from the CSV file but I seem to be unable to return the result.
Pretty sure this is a problem with the way I handle async execution but I fail to see what I am doing wrong.
I've spent the last 2 days reading about this (including the threads around here) and browsing but somehow the answer still escapes me.
First file - usercms.js
app.get('/userscms', function(req, res)
{
existingUsers.getExistingUsers()
.then(function(appUsers)
{
//global users array
//I can display these in my ejs file
globalAppUsers = appUsers;
})
.then(existingUsersAttributesQlik.getExistingUsersAttributesQlik())
.then(function(usersQlikAttributes)
{
//global user attributes array
//undefined data
globalUsersQlikAttributes = usersQlikAttributes;
})
.then(existingSuppliers.parseSuppliersCSV())
.then(function(supplierData)
{
//the result I am expecting
//this prints undefined
console.log(supplierData);
}).then(function()
{
res.render('userscms.ejs',
{
users: globalAppUsers,
attributes: globalUsersQlikAttributes
});
});
});
Second function - getxistingUsers.js (identical to the getExistingUsersAttributesQlik, except for the query)
var userData = [];
var appUsers = [];
(function (exports)
{
exports.getExistingUsers = function ()
{
return promisemysql.createConnection(dbconfig.development).then(function(conn)
{
var result = conn.query("SELECT id, username, firstName, lastName, email, phone, lastLogin, isAdmin, isValid, isPhoneValid, accountCreationDateTime FROM Users");
conn.end();
return result;
}).then(function(rows)
{
return rows;
}).then(function(rows)
{
if (rows.length)
{
userData = [];
appUsers = [];
rows.forEach(function (elem)
{
userData.push(_.toArray(elem));
});
for (i = 0; i < userData.length; i++)
{
var appUser = new appUserModel.AppUser(
userData[i][0],
userData[i][1],
userData[i][2],
userData[i][3],
userData[i][4],
userData[i][5],
userData[i][6],
userData[i][7],
userData[i][8],
userData[i][9],
userData[i][10]);
appUsers.push(_.toArray(appUser));
}
return appUsers;
}
else
{
console.log("NOPE");
return null;
}
}).then(function(appUsers)
{
console.log(appUsers);
return appUsers;
});
};
})(typeof exports === 'undefined' ? this['getExistingUsers'] = {} : exports);
Third file - parseSuppliersCSV.js
var supplierData = [];
var suppliersData = [];
var csvCount = 0;
(function (exports)
{
exports.parseSuppliersCSV = function ()
{
return new Promise(function(resolve, reject)
{
var fileStream = fs.createReadStream("myCSV.csv");
var parser = fastCsv();
csvCount = 0;
supplierData = [];
suppliersData = [];
fileStream
.on("readable", function ()
{
var data;
while ((data = fileStream.read()) !== null)
{
parser.write(data);
}
})
.on("end", function ()
{
parser.end();
});
parser
.on("readable", function ()
{
var data;
while ((data = parser.read()) !== null)
{
if(csvCount >= 1)
{
csvCount++;
var arrayOfStrings = data[0].split(';');
var supplier = new supplierModel.Supplier(arrayOfStrings[0],arrayOfStrings[1]);
suppliersData.push(_.toArray(supplier));
}
else
{
csvCount++;
}
}
})
.on("end", function ()
{
console.log("done");
//all OK here
console.log(suppliersData);
//this doesn't seem to return anything
return suppliersData;
});
});
};
})(typeof exports === 'undefined' ? this['parseSuppliersCSV'] = {} : exports);
Any ideas what I am doing wrong? Am I approaching this the wrong way?
I'll take a guess here and assume the promise you created should resolve to something...instead of returning a value.
.on("end", function ()
{
console.log("done");
//all OK here
console.log(suppliersData);
//this doesn't seem to return anything
return resolve(suppliersData);
});
My server has a route,
app.get(("/employees/:id"), (req, res) => {
console.log(req.paramas.id); //prints correctly
data.getEmployeeByNum(req.params.id).then((data) => {
res.json(data);
}).catch(function(reason) {
console.log("An error was encountered: " + reason);
});
});
And getEmployeeByNum() is defined as,
module.exports.getEmployeeByNum = function(num) {
return new Promise((reject, resolve) => {
var temp = [];
let j = 0;
for (let i = 0; i < employees.length; i++) {
if (employees[i].employeeNum == num) {
temp[j] = employees[i];
j++;
}
}
console.log("LENGTH IS: " + temp.length); //LENGTH IS: 1 (which is exactly what I need)
if (temp.length == 0) {
console.log("we bad");
reject("No results");
} else {
console.log("we good"); //prints this line
resolve(temp);
}
});
}
As you can note, console.log("we good"); gets called as it should, and my function resolves the array of one employee. But my call to this function catches it as an error, and prints An error was encountered: [object Object]. Any thoughts? Im breaking my head over this.
Im an idiot.
module.exports.getEmployeeByNum = function(num) {
return new Promise((resolve, reject) => {
not
module.exports.getEmployeeByNum = function(num) {
return new Promise((reject, resolve) => {
I am trying to iterate through the JSON files generated by the protractor tests. I pull all the file names into an array and call a method that opens and parses through the each file, post the results to the database and pass back a passed/failed flag.
I have tried all the examples here
Make angular.forEach wait for promise after going to next object and still get the same results.
The method is actually called, but the results are not posted to the db. I have tested the parser.parseResults on an individual file and it successfully posted to the db, so it has to have something to do with the promise not resolving correctly.
Is it not possible to do something like this in the jasmine/protractor framework? Or do I have something wrong in the code?
I have included the code for my latest attempt.
Thank You
Christine
matches.reduce(function (p, val) {
console.log('val', val);
return p.then(function () {
return parser.parseResults(val);
});
}, Promise.resolve()).then(function (finalResult) {
console.log('finalResult = ', finalResult);
}, function (err) {
console.log('error in reduce',err);
});
parser.parseResults code
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
try {
if (err != null) {
console.log('error reading file',err);
reject(err);
}
console.log('obj - ',obj);
var results = [];
var Passed = 0;
var Message = '';
var Stack = '';
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
if (specs.length > 0) {
for (var i = 0; i < specs.length; i++) {
var assert = specs[i];
var tcR = new RegExp(/TC[\d]+/);
var tc = assert.description.match(tcR);
if (!assert.failedExpectations.length) {
Passed = 1;
}
else {
assert.failedExpectations.forEach((expectation) => {
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
})
Passed = 0;
}
if (tc != null) {
utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild,
'P', Message, Stack, 0, moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss'), '')
.then(function (resp) {
resolve(Passed);
}, (err) => {
console.log('Posting to Database failed ', err);
reject(err);
});
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
reject(err);
}
}
}
}
}
catch (err) {
console.log('rejecting opening file');
reject(err);
}
});
})
}
If there is not exactly one suite in the obj, with exactly one spec, then your promise is either resolved not at all or multiple times.
Avoid wrapping too many things in the new Promise constructor - always promisify on the smallest possible level, and use promise chaining afterwards.
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
if (err != null) {
console.log('error reading file', err);
reject(err);
} else {
resolve(obj);
}
});
}).then(function(obj) {
console.log('obj - ',obj);
var results = [];
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
for (let i = 0; i < specs.length; i++) {
const assert = specs[i];
const tcR = /TC[\d]+/;
const tc = assert.description.match(tcR);
let Passed = 1;
let Message = '';
let Stack = '';
if (assert.failedExpectations.length) {
const expectation = assert.failedExpectations[assert.failedExpectations.length-1];
Passed = 0;
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
}
if (tc != null) {
const time = moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss');
const promise = utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild, 'P', Message, Stack, 0, time, '');
results.push(promise.catch(err => {
console.log('Posting to Database failed ', err);
throw err;
}));
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
// I don't think you want to `throw err` here, right?
}
}
}
return Promise.all(results);
});
};
I'm messing with SteamAPI in order to learn some NodeJS. Right now I'm trying to get games's info after an initial request to get the player's profile, once I have the games IDs stored in an array. The point is that I don't know how to "return" an array AFTER the whole ID array is iterated and all results has come from the server.
function getThumbs(game) {
return rq(
'http://store.steampowered.com/api/appdetails?appids=' + game,
{json: true},
function (error, response, bd) {
if(response.statusCode === 200 && bd[game].data) {
return bd[game].data.screenshots;
}
});
}
function getGamesThumbnails(games) {
var deferred = $q.defer(),
queue = [];
for (var y = 0; y < games.length; y++) {
var game = games[y];
var thumbs = getThumbs(game);
queue.push(thumbs);
}
$q.all(queue).then(
function (data) {
deferred.resolve(data);
},
function (err) {
deferred.reject(err)
}
);
return deferred.promise;
}
app.get('/blog',function(client_req,client_res){
rq('http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=' + key + '&steamid=blablabla&format=json', function (error, response, body) {
var data = JSON.parse(body);
var games = data.response.games.map(function (game) {
return game.appid;
});
getGamesThumbnails(games).then(function (data) {
console.log(data)
})
});
});
Basically, you should use a callback, because like you are doing in getThumbsyou are returning the object, while you should return the value bd[game].data.screenshots;
function getThumbs(game, cb) {
return rq(
'http://store.steampowered.com/api/appdetails?appids=' + game,
{json: true},
function (error, response, bd) {
if(response.statusCode === 200 && bd[game].data) {
cb(null, bd[game].data.screenshots);
}
});
}
function getGamesThumbnails(games) {
var deferred = $q.defer(),
queue = [];
for (var y = 0; y < games.length; y++) {
var game = games[y];
getThumbs(game, function(err, value) {
queue.push(value);
});
}
$q.all(queue).then(
function (data) {
deferred.resolve(data);
},
function (err) {
deferred.reject(err)
}
);
return deferred.promise;
}
And plust to return the response to the client you have to use the client_res.send(VALUE)
so the bottom part would become like this:
app.get('/blog',function(client_req,client_res){
rq('http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=' + key + '&steamid=blablabla&format=json', function (error, response, body) {
var data = JSON.parse(body);
var games = data.response.games.map(function (game) {
return game.appid;
});
getGamesThumbnails(games).then(function (data) {
client_res.send(data);
console.log(data)
})
});
});
Your getThumbs() function does not return a promise. $q.all only works on an array containing promises, whereas rq uses callbacks.
Try this:
function getThumbs(game) {
var deferred = $q.defer(),
rq(
'http://store.steampowered.com/api/appdetails?appids=' + game,
{json: true},
function (error, response, bd) {
if(response.statusCode === 200 && bd[game].data) {
deferred.resolve(bd[game].data.screenshots);
}
});
return deferred.promise;
}
Thank you both!
I tried Yuri's approach, but $q.all it doesn't seem to resolve the array of promises (nothing happens after the last request from getThumbs())
for (var y = 0; y < games.length; y++) {
var game = games[y];
var thumbs = getThumbs(game);
queue.push(thumbs);
}
$q.all(queue).then(
function (data) {
console.log(data)
deferred.resolve(data);
},
function (err) {
deferred.reject(err)
}
);
I'm new to promise, and trying to use promise in a for loop.
function query(queryString, keywords) {
var defer = q.defer();
connection.query(queryString + '"' + keywords + '"', function (err, rows) {
if (err) {
defer.reject(err);
} else {
defer.resolve(rows[0]);
}
});
return defer.promise;
}
q.all([
query(testQuery, 'test1'),
query(testQuery, 'test2')
]).then(console.log, console.log);
The above code is working and returns an array of results.
What I am trying to do is to use a for loop so I don't need to write the query every time.
query(testQuery, 'test1'),
query(testQuery, 'test2'),
query(testQuery, 'test3'),
query(testQuery, 'test4')
And here is my updated code:
function query(queryString, keywords) {
var defer = q.defer(),
results = [];
for (var i = 0; i < keywords.length; i++) {
connection.query(queryString + '"' + keywords[i] + '"', function (err, rows) {
if (err) {
defer.reject(err);
} else {
results.push(rows[0]);;
}
});
}
defer.resolve(results);
return defer.promise;
}
var tests = ['test1', 'test2'];
q.all(query(testQuery, tests)).then(console.log, console.log);
And the above code is not working which returns an empty array.
This seems not to be the correct way to use a for loop for promises. So in this case, how can I return an array of promises after a for loop?
Thanks.
Updated version (Based on #Bergi's comment):
function query(queryString, keywords) {
var defer = q.defer();
connection.query(queryString + '"' + keywords + '"', function (err, rows) {
if (err) {
defer.reject(err);
} else {
defer.resolve(rows[0]);
}
});
return defer.promise;
}
var tests = ['test1', 'test2'],
results = [];
for (var i = 0; i < tests.length; i++) {
results.push(query(testQuery, tests[i]));
}
q.all(results).then(console.log, console.log);
This is working, but I wonder if there is a way to include the for loop inside the query function. As I have to write a for loop every time when using this method.
It should look something like this:
function query(queryString, keywords) {
var promiseArr = [];
for (var i = 0; i < keywords.length; i++) {
var deferred = $q.defer();
promiseArr.push(deferred.promise);
connection.query(queryString + '"' + keywords[i] + '"', function (def) {
return function (err, rows) {
if (err) {
def.reject(err);
} else {
def.resolve(rows[0]); // what is rows and why just rows[0]???
}
};
}(deferred));
}
return promiseArr;
}
var tests = ['test1', 'test2'];
q.all(query(testQuery, tests)).then(console.log, console.log);
Here is a version that uses the underscore library to get your desired results. You are going to have to use something that adds a level of scoping. Both native map and underscore map will work
function query(queryString, keywords) {
return _.map(keywords, function(keyword) {
return Q.promise(resolve, reject) {
connection.query(queryString + '"' + keyword + '"', function (err, rows) {
if (err) {
reject(err);
} else {
resolve(rows[0]);
}
});
};
});
}
var tests = ['test1', 'test2'],
results;
q.all(query(testQuery, tests).then(console.log, console.log);