Node.js promises using Q - javascript

I have a Node app that I'm writing where I need to use promises for async calls.
I currently have a foreach loop being called from within a .then(function()) of a promise, but when I return the end result of the foreach, I get nothing.
In the foreach I can console.log the value of data and retrieve it, but not outside the for loop before the return?
var Feeds = function(){
this.reddit = new Reddit();
}
Feeds.prototype.parseRedditData = function(){
var _this = this;
this.getData(this.reddit.endpoint).then(function(data){
return _this.reddit.parseData(data, q);
});
}
Feeds.prototype.getData = function(endpoint){
var deferred = q.defer();
https.get(endpoint, function(res) {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
deferred.resolve(JSON.parse(body));
});
}).on('error', function(e) {
deferred.reject(e);
});
return deferred.promise;
}
var Reddit = function(){
this.endpoint = "https://www.reddit.com/r/programming/hot.json?limit=10";
}
Reddit.prototype.parseData = function(json, q){
var dataLength = json.data.children.length,
data = [];
for(var i = 0; i <= dataLength; i++){
var post = {};
post.url = json.data.children[i].data.url;
post.title = json.data.children[i].data.title;
post.score = json.data.children[i].data.score;
data.push(post);
}
return data;
}

Feeds.prototype.parseRedditData = function(){
var _this = this;
this.getData(this.reddit.endpoint).then(function(data){
return _this.reddit.parseData(data, q);
});
}
When i see this I see a "return" in the callback of the promise... I don't know why you're doing this, but I just want to be sure:
I you want this "return" to be the returned value of the function 'parseRedditData', this won't work.
The only way to return your data here is by using a callback, or a promise, like this:
Feeds.prototype.parseRedditData = function(callack){
var _this = this;
this.getData(this.reddit.endpoint).then(function(data){
callback(_this.reddit.parseData(data, q));
});
}

Related

how to make async html parser in nodejs with promises?

having fun with promises in JS and trying to craft simple xpath website parser, but I am struggling with logic on finishing overall parsing process, my code is:
var request = require('request');
var xpath = require('xpath');
var dom = require('xmldom').DOMParser;
var olxMain = 'https://www.some.site/';
var xpathRoot = '//a[contains(#href, "https://www.some.site/mask/")]';
var linksXpath = '//a';
var allGlobalLinks = [];
var getLink = function (node) {
for (key in node['attributes']) {
if (node['attributes'][key]['name'] === 'href') {
return node['attributes'][key]['value'];
}
}
}
var getData = function (url, xpathPattern) {
return new Promise(function (resolve, reject) {
console.log("Opening " + url);
var processResponse = function (error, response, body) {
var doc = new dom().parseFromString(body);
var childNodes = xpath.select(xpathPattern, doc);
var links = childNodes.map(function (n) {
return getLink(n);
});
resolve(links);
};
request({url: url}, processResponse);
}
);
}
var arrayUnique = function (x, i, a) {
return a.indexOf(x) == i;
};
var main = function () {
getData(olxMain, xpathRoot).then(function (links) {
links = links.filter(arrayUnique);
var maxThreads = 10, n = 0;
var chunks = [];
for (k in links) {
var url = links[k];
n++;
if (n <= maxThreads)
chunks.push(url);
else {
n = 0;
// console.log(chunks);
Promise.all(chunks.map(function (url) {
return getData(url, linksXpath);
})).then(function (links) {
// add these links to global scope list here
});
console.log("Finished mappings iteration");
});
chunks = [];
}
}
;
});
}
main();
So what I want is basically some kind of threadPool with promises, how to I manage these 10 promises, when they all are finished, I should spawn another 10 more, until list is finished and all Promises have finished ?

How to make async request in cycle?

var userName = 'realgrumpycat';
var moreAvailable = true;
var lastId = '';
while (moreAvailable)
{
getPhotosDataFromRequest(userName, lastId).then(function (data)
{
moreAvailable = data.more_available;
lastId = data[data.length - 1].id;
console.log(data);
});
}
getPhotosDataFromRequest() returns new Promise() and JSON with data. I'd like to execute this method several times at cyscle. But as I see at debugger, while loop executes so fast, that doesn't step into promise then block
Try using function recursion:
var userName = 'realgrumpycat';
var lastId = '';
var getPhotos = function()
{
getPhotosDataFromRequest(userName, lastId).then(function (data)
{
lastId = data[data.length - 1].id;
console.log(data);
if (data.more_available)
{
getPhotos();
}
});
};
getPhotos();
just as iterative alternative (as concept), but not really a solution in real life, because of performance and limits:
//i try to use here es5 only
var userName = 'realgrumpycat';
var moreAvailable = true;//<-- can be removed
var lastId = ''; //<-- can be removed
var maxRequests = 1000; //e.g. max 1000 requests
//create empty promise to resolve later
var resolveStart = null;
var request = new Promise(function(resolve){
resolveStart = resolve;
});
//append 1000 potential requests
for(var i = 0; i < maxRequests; i++) {
request = request.then(createRequestPromise);
}
//here you probably should differ the "done" rejection and other errors
request.catch(function(){});
//now resolve the first promise, with empty string, to start the request chain
resolveStart('');
function createRequestPromise(lastId) {
return getPhotosDataFromRequest(userName, lastId).then(function (data)
{
lastId = data[data.length - 1].id;
console.log(data);
//stop the chain by rejection
if (!data.more_available) return Promise.reject('done');
return lastId;
});
}

NodeJS: Use Promises in Loop with Q

I have a problem with promises in a loop. The whole promise thing is completely new to me, so I try to learn it with very simple examples.
In my example, I have 2 text files on a server and I want to save the content of the text files into an array.
It works with a setTimeout, but this is not the solution that I want. Here is the example wit setTimeout
var http = require('http'),
Q = require('q');
var urls = ["http://localhost:8000/1.txt", "http://localhost:8000/2.txt"]
var txts = [];
function getData(url) {
http.get(url, function(res) {
var data = "";
res.on('data',function(chunk){
data+=chunk;
});
res.on('end',function(){
txts.push(data);
});
}).on('error',function(e){
console.log("Error Request: "+e.message);
})
}
function getTxts() {
for(a in urls) {
var url = urls[a];
getData(url);
}
// is not working
console.log(txts);
// is working
setTimeout(function() {
console.log(txts);
}, 1000)
}
getTxts();
I now tried doing it with Q, but I am stuck at some point. There is some point where I am going into the wrong direction, but I can't see where it is.
var http = require('http'),
Q = require('q');
var urls = ["http://localhost:8000/1.txt", "http://localhost:8000/2.txt"]
var txts = [];
function getData(url) {
return Q.promise(function(respond,reject){
http.get(url, function(res) {
var data = "";
res.on('data',function(chunk){
data+=chunk;
});
res.on('end',function(){
txts.push(data);
});
}).on('error',function(e){
console.log("Error Request: "+e.message);
})
});
}
function getTxts() {
var promises = [];
for(a in urls) {
var url = urls[a];
var promise = getData(url);
promises.push(promise);
}
return promises;
}
function start() {
Q.fcall(function() {
getTxts();
}).then(function() {
console.log(txts);
})
}
start();
Thanks for your help!
You could use just regular promises for this
var http = require('http');
var urls = ["http://localhost:8000/1.txt", "http://localhost:8000/2.txt"]
function getData(url) {
return new Promise(function(resolve, reject) {
http.get(url, function(res) {
var data = "";
res.on('data',function(chunk){
data+=chunk;
});
res.on('end',function(){
resolve(data);
});
}).on('error',function(err){
reject(err);
});
});
}
function getTxts() {
return Promise.all(
urls.map(function(url) {
return getData(url);
})
);
}
getTxts().then(function(texts) {
// "texts" is an array of the returned data
}).catch(function(err) {
// epic fail
});
Issue is you are not resolving or rejecting the promise you created in the getData function
function getData(url) {
return Q.promise(function(resolve,reject){
http.get(url, function(res) {
var data = "";
res.on('data',function(chunk){
data+=chunk;
});
res.on('end',function(){
txts.push(data);
resolve(); // resolve the promise when done
});
}).on('error',function(e){
console.log("Error Request: "+e.message);
reject(); // reject the promise if there is an error
})
});
}

jQuery.Deferred() is not working properly

I'm trying to implement indexedDB. For that I need to use $.Deferred to get the status of database creation. But the problem is, Differed is not working as expected.
Here is the fiddle, you can find the process in the console.
And here is the code:
$(function($) {
var table = 'price';
$.when(dbConnection('cw', table)).done(function(db) {
console.log(db);
var data = [];
dbInsert(db, data, table);
});
function dbConnection(dbname, table) {
var dfd = $.Deferred();
var request = indexedDB.open(dbname);
request.onupgradeneeded = function() {
// The database did not previously exist, so create object stores and indexes.
var db = request.result;
var store = db.createObjectStore(table, {
keyPath: "id"
});
var styleCode = store.createIndex("style_code", "style_code");
var colorCode = store.createIndex("color_code", "color_code");
var size = store.createIndex("size", "size");
var price1 = store.createIndex("price1", "price1");
};
request.onsuccess = function() {
db = request.result;
console.log(request.result);
dfd.resolve(db);
return dfd.promise();
};
request.onerror = function() {
report(request.error);
console.log(request.error);
dfd.resolve(null);
return dfd.promise();
};
request.onabort = function() {
report(request.error);
console.log(request.error);
dfd.resolve(null);
return dfd.promise();
};
}
function dbInsert(db, data, table) {
var tx = db.transaction(table, "readwrite");
var store = tx.objectStore(table);
$.each(data, function(i, rows) {
var style = rows['style-code'],
color = rows['color-code'],
size = rows['size'],
price = rows['price1'];
store.put({
id: i,
style_code: style,
color_code: color,
size: size,
price1: price
});
});
tx.oncomplete = function() {
console.log('Data inserted successfully.');
};
}
})(jQuery);
Whether I'm doing anything wrong? or am I missing anything in this code?. Can anyone tell me what is wrong in this code.
You are expecting dbConnection to return a promise, but do not return anything from that function. Return the promise immediately (last line below) and not inside all the callbacks:
function dbConnection(dbname, table) {
var dfd = $.Deferred();
var request = indexedDB.open(dbname);
request.onupgradeneeded = function() {
// The database did not previously exist, so create object stores and indexes.
var db = request.result;
var store = db.createObjectStore(table, {
keyPath: "id"
});
var styleCode = store.createIndex("style_code", "style_code");
var colorCode = store.createIndex("color_code", "color_code");
var size = store.createIndex("size", "size");
var price1 = store.createIndex("price1", "price1");
};
request.onsuccess = function() {
db = request.result;
console.log(request.result);
dfd.resolve(db);
};
request.onerror = function() {
report(request.error);
console.log(request.error);
dfd.resolve(null);
};
request.onabort = function() {
report(request.error);
console.log(request.error);
dfd.resolve(null);
};
return dfd.promise();
}
Updated JSFiddle: http://jsfiddle.net/TrueBlueAussie/9kjcm49b/2/
Your various callbacks simply resolve or reject the deferred. The readonly promise returned earlier then triggers the next operation.
Note: You should probably use reject for the two error cases (unless you actually want to proceed with a null db value). e.g.
request.onerror = function() {
report(request.error);
console.log(request.error);
dfd.reject("Error occurred");
};
request.onabort = function() {
report(request.error);
console.log(request.error);
dfd.reject("Operation aborted");
};
and use like this:
$.when(dbConnection('cw', table)).done(function(db) {
console.log(db);
var data = [];
dbInsert(db, data, table);
}).fail(function(message){
alert(message);
});

Why my jquery .get() result could not show by order i give

I am trying to make a google shortener analytic tools by javascript, it's my code:
<script>
function makeRequest() {
for (var i=0; i < shortUrl.length; i++){
var url = shortUrl[i];
var request = gapi.client.urlshortener.url.get({
'shortUrl': url,
'projection':'FULL',
});
request.execute(function(response) {
console.log(response); //here is the problem begin
var result = {
short: response.id,
clicks: response.analytics.allTime.shortUrlClicks
};
appendResults(result, i);
});
}
}
function load() {
gapi.client.setApiKey('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
gapi.client.load('urlshortener', 'v1', makeRequest);
}
</script>
<script src="https://apis.google.com/js/client.js?onload=load"></script>
the result would me different everytime!
ex:
shortUrl[1,2,3,4]
it will return 3,2,1,4 or 1,2,4,3......etc
what's wrong is my code?
is the async problem? how could i fix it?
please help me!
thx
Because ajax is asynchronous. You have to use promises.
jQuery example.
var promises = [];
for (var i=0; i < shortUrl.length; i++){
var dfd = new $.Deferred;
var url = shortUrl[i];
var request = gapi.client.urlshortener.url.get({
'shortUrl': url,
'projection':'FULL',
});
request.execute((function(dfd){return function(response) {
dfd.resolve(response);
};})(dfd));
promises.push(dfd.promise());
}
$.when.apply($, promises).done(function(){
promises = undefined;
for(var i in arguments){
var response = arguments[i];
console.log(response); //here is the problem begin
var result = {
short: response.id,
clicks: response.analytics.allTime.shortUrlClicks
};
appendResults(result, i);
}
});
My working code:
var promises = [];
var request = function(i, callback){
setTimeout(function(){return callback(i);},100 - i);
}
for (var i=0; i < 10; i++){
var dfd = new $.Deferred;
request(i, (function(dfd){return function(response) {
dfd.resolve(response);
};})(dfd));
promises.push(dfd.promise());
}
$.when.apply($, promises).done(function(){
promises = undefined;
for(var i in arguments){
console.log(arguments[i]);
}
});

Categories

Resources