Returning data that came from Promise - javascript

I'm creating a script which reads data from pdf in node, I'm using pdf_text_extract, and I'm trying to return the data with Bluebird.
Types.js:
var pdf = require('pdf');
var Types = {
read: function(file, extension) {
pdf.extract(file, function(error, data) {
console.log(data);
});
}
};
module.exports = Types;
The data is a [Function], this is clearly wrong.
Pdf.js:
var Promise = require('bluebird');
var pdf_text_extract = require('pdf-text-extract');
var Pdf = {
extract: function(file, cb) {
return new Promise(function(resolve, reject) {
if (reject) {
console.log(reject);
}
pdf_text_extract(file, function(error, data) {
if (error) {
console.log(error);
}
resolve(data);
});
});
}
};
module.exports = Pdf;
I'm trying to access the data in other archive, which is calling the Types.js.

No, the data is not a function. The cb function you're passing is completely ignored and never executed, the log you are seeing is from console.log(reject); (as reject is always truthy).
Correct would be
var pdf = {
extract: function(file) {
return new Promise(function(resolve, reject) {
pdf_text_extract(file, function(error, data) {
if (error)
reject(error);
else
resolve(data);
});
});
}
};
var types = {
read: function(file, extension) {
return pdf.extract(file).then(function(data) {
console.log(data);
}, function(error) {
console.log(error);
});
// returns a promise that fulfills with undefined once data or error are received
}
};
Or much simpler
var pdf = {
extract: Promise.promisify(pdf_text_extract)
};

Related

While call rest api in Javascript (NodeJS) and return response Undefined

When i call rest API and return response it show undefined but i console.log this response it return
var request = require("request");
function initialize() {
// Setting URL and headers for request
var options = {
url: 'http://postalpincode.in/api/pincode/400605',
json: true
};
// Return new promise
return new Promise(function (resolve, reject) {
// Do async job
request.get(options, function (err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.stringify(body));
}
})
})
}
function main() {
var initializePromise = initialize();
initializePromise.then(function (result) {
return result;
})
}
console.log('', main())
But when i console log this response it show output correct
var request = require("request");
function initialize() {
// Setting URL and headers for request
var options = {
url: 'http://postalpincode.in/api/pincode/400605',
json: true
};
// Return new promise
return new Promise(function (resolve, reject) {
// Do async job
request.get(options, function (err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.stringify(body));
}
})
})
}
function main() {
var initializePromise = initialize();
initializePromise.then(function (result) {
console.log('', result)
})
}
console.log('', main())
I want When i call rest API and return response it show correct output
The return inside the thenscope is not returning for the function main, but only for the thenscope of the promise. You need to return the promise like so:
function main() {
var initializePromise = initialize();
return initializePromise.then(function (result) {
return result;
})
}
main().then((result) => console.log('',result));
you can't make a sync function call an async method and expect to have get its result.
use async/await
async function main() {
var initializePromise = await initialize();
console.log(initializePromise)
}
My question is, why are you wrapping in a new Promise something that's already from a return type of Promise?
You could just do:
request.get(endpoint, options).then((response) => console.log(response)).catch((error) => console.log(error));
Let me know what's the output in that case.
The then resolution of initializePromise method resolves at a later stage when a response is fetched from REST HTTP call i.e. it does not get returned when you call main() method due to the fact it is async. To handle such code, you should either use a callback
function main(completionHandler) {
var initializePromise = initialize();
initializePromise.then(function (result) {
completionHandler(result);
})
}
main((result) => { console.log(result)})
or a promise
function main() {
// Return new promise
return new Promise(resolve => {
var initializePromise = initialize();
initializePromise.then(function (result) {
resolve(result);
})
}
}
main().then(result => console.log(result));
return new Promise(function (resolve, reject) {
// Do async job
request.get(options, function (err, resp, body) {
if (err) {
reject(err);
} else {
try {
resolve(JSON.stringify(body));
} catch(e) {
reject(e);
}
}
})
})
in main function:
function main() {
initialize().then((result) => {
console.log(result);
return result;
}).catch((err) => {
console.log(err);
return err;
})
}

How to use json response to create another URL. Nodejs

I have the question, below code:
The problem is:
How can I send each line from response promiseGetCitiesData to promiseGetInformationDataPerCity.
Can I do it in one async.each functions?
Now, I created multiple Promise functions. One general function, which one start the program - getDataAndCloseDb().
Also I used async.each to call promise function with array parameter - locationArray.
Now, I would like to send each line from json response to next promise function (create get url), and collect the general response.
const MongoClient = require("mongodb").MongoClient;
const request = require("request");
const async = require("async");
var locationsArray = [
'location1',
'location2',
'location3'
];
function promiseConnectToDatabase(urldb) {
return new Promise(function(resolve, reject) {
MongoClient.connect(urldb, (err, db) => {
if (err) {
console.log("MongoDb connection error.");
reject(err);
}
console.log("Connected to MongoDb.");
resolve(db);
});
});
}
function promiseGetCitiesData(location) {
return new Promise(function(resolve, reject) {
request({
url: `https://example.com/${location}`,
json: true
}, (error, response, body) => {
if (error) {
console.log("Error connection to url.");
reject();
}
console.log("location: " + location);
console.log({location: location, cities: body.result.cities});
resolve({location: location, cities: body.result.cities});
});
});
}
/*
Example response from promiseGetCitiesData:
Location: location1
{ location: 'location1',
cities:
[ 'information1',
'information2',
'information3',
'information4'' ] }
*/
function promiseGetInformationDataPerCity(location, cities) {
return new Promise(function(resolve, reject) {
request({
url: `https://example.com/${location}/${cities}`,
//f.e https://example.com/location1/information1 etc.
json: true
}, (error, response, information) => {
if (error) {
console.log("Error connection to url.");
reject();
}
console.log(information);
resolve(information);
});
});
}
function promiseSaveDataToDatabase(db, body) {
return new Promise(function(resolve, reject) {
db.collection("testlocation").insert(body, function(dbError) {
if (dbError) {
reject(dbError);
}
resolve()
});
});
}
function promiseDisconnectDatabase(db) {
return new Promise(function(resolve, reject) {
db.close((err) => {
if (err) {
console.log("MongoDb disconnect error.");
reject(err);
}
console.log("MongoDb disconnected.");
resolve();
});
});
}
function promiseProvideDataFromEach(locationsArray, db) {
return new Promise(function(resolve, reject) {
async.each(locationsArray, function(loc, locProcessedCb) {
promiseGetcitiesData(loc).then(function(resultscities) {
promiseGetInformationDataPerCity(loc, resultscities).then(function(resultDetails) {
promiseSaveDataToDatabase(db, resultDetails).then(function() {});
locProcessedCb();
});
});
}, function(err) {
if (err) {
locProcessedCb(err);
reject(err);
}
console.log("All locations have been processed.");
resolve();
});
});
}
function getDataAndCloseDb() {
return new Promise(function(resolve, reject) {
promiseConnectToDatabase("mongodb://127.0.0.1:27017/testApp").then(function(db) {
promiseProvideDataFromEach(locationsArray, db).then(function() {
promiseDisconnectDatabase(db).then(function() {});
});
});
});
}
getDataAndCloseDb();
I think this is a lot simpler than the code in the question makes it appear. In particular, new Promise(...) can be completely avoided by :
using require('async-request') instead of require('request').
allowing MongoDb methods to return Promise, as many of them will do if no callback is passed.
Also
by using the Promise.all(array.map(...)) pattern the need for require('async') disappears.
https://stackoverflow.com/a/28915678/3478010 - provides a great little reusable disposer utility, which is useful here.
Remember to return a promise/value from every .then() callback that is itself asynchronous and/or should deliver data.
With some guesswork, I think you want something like this :
const MongoClient = require('mongodb').MongoClient;
const request = require('async-request'); // just like `request()` but returns a promise
var locationsArray = [
'location1',
'location2',
'location3'
];
function promiseGetCitiesData(loc) {
return request({
url: `https://example.com/${loc}`,
json: true
}).then(body => body.result.cities);
}
function promiseGetInformationDataPerCity(loc, cities) {
return Promise.all(cities.map(city => {
return request({
'url': `https://example.com/${loc}/${city}`,
'json': true
}).then(cityInfo => ({ 'name':city, 'info':cityInfo }));
}));
}
function promiseProvideDataFromEach(locationsArray, db) {
return Promise.all(locationsArray.map(loc => {
return promiseGetCitiesData(loc)
.then(cities => promiseGetInformationDataPerCity(loc, cities)
.then(citiesWithCityInfo => ({ 'location':loc, 'cities':citiesWithCityInfo }));
}))
.then(resultDetails => db.collection('testlocation').insertMany(resultDetails));
}
// disposer utility - credit: https://stackoverflow.com/a/28915678/3478010
function withDb(work) {
var _db;
return MongoClient.connect("mongodb://127.0.0.1:27017/testApp")
.then((db) => {
_db = db; // keep reference
return work(db); // perform work on db
}).finally(() => {
if (_db)
_db.close();
});
}
withDb(db => promiseProvideDataFromEach(locationsArray, db))
.then(() => {
// connection released here
});
The guesswork centres mainly around what is to be inserted at db.collection('testlocation').insertMany(resultDetails). The code in the question gives no more than a clue. My attempt seems reasonable but may not be exactly what you want. Be prepared to make some changes in promiseProvideDataFromEach() and promiseGetInformationDataPerCity().
you can do something like this. Its a simpler code but I think you can map it to your current code.
const Promise = require('bluebird')
const cities = ['citya', 'cityb', 'cityc']
function resolveCities() {
return new Promise(function(resolve, reject) {
resolve(cities)
})
}
function logCity(city) {
console.log('city ', city)
}
return resolveCities()
.then(function(cities) {
return Promise.mapSeries(cities, function(city) {
logCity(city);
});
})

How to return a promise when out of scope?

I want to retrieve multiple files asynchronously from AWS S3 so I am using Promises.
I am using AWS S3 to retrieve the files. However, fulfill is out of scope. I am getting the following error;
ReferenceError: reject is not defined
What would be the correct way to return a Promise in this circumstance and how would it be best to provide a key to files with the data returned from S3?
var getFiles = function getFiles(files) {
return Promise.all(files.map(function(file) {
var params = {
Bucket: 'my-bucket',
Key: file.key
}
s3.getObject(params, function(err, data) {
if (err) reject(err);
else {
// set key.data = data
fulfill(data);
}
});
}));
}
var fileNames = ['file1.jpg', 'file2.jpg'];
var files = fileNames.map(function(fileName) {
return {
key: fileName,
}
});
getFiles(files);
Promise.all expects an array of promises. Right now your callback inside the map function is not returning a promise. You can fix this by updating the code to the following:
var getFiles = function getFiles(files) {
return Promise.all(files.map(function (file) {
return new Promise((resolve, reject) => {
var params = {
Bucket: 'app-design.aiir.net',
Key: file.key
};
s3.getObject(params, function (err, data) {
if (err) reject(err);
else {
// set key.data = data
resolve(data);
}
});
});
}));
};
var fileNames = ['file1.jpg', 'file2.jpg'];
var files = fileNames.map(function (fileName) {
return {
key: fileName,
}
});

Recursively calling asynchronous function that returns a promise

I'm trying to recursively call AWS's SNS listEndpointsByPlatformApplication. This returns the first 100 endpoints then a token in NextToken if there are more to return (details: AWS SNS listEndpointsByPlatformApplication).
Here's what I've tried:
var getEndpoints = function(platformARN, token) {
return new models.sequelize.Promise(function(resolve, reject) {
var params = {
PlatformApplicationArn: platformARNDev
};
if (token != null) {
params['NextToken'] = token;
}
sns.listEndpointsByPlatformApplication(params, function(err, data) {
if (err) {
return reject(err);
}
else {
endpoints = endpoints.concat(data.Endpoints); //save to global var
if ('NextToken' in data) {
//call recursively
return getEndpoints(platformARN, data.NextToken);
}
else {
console.log('trying to break out!');
return resolve(true);
}
}
});
});
}
I'm calling it with:
getEndpoints(platformARNDev, null)
.then(function(ret) {
console.log('HERE!');
}, function(err) {
console.log(err);
});
Problem is: the first call happens, then the recursive call happens, and I get the message trying to break out! but the HERE! never gets called. I've got something wrong with how my promises are returning I think.
Grateful for pointers.
The problem is that you try and resolve/reject partially completed query. Here is a complete working example with dummy service. I incapsulated the data grabbing into it's own recursive function and only do resolve/reject when i've completely fetched all the data or stumbled upon an error:
// This is the mock of the service. It yields data and token if
// it has more data to show. Otherwise data and null as a token.
var dummyData = [0, 1, 2, 3, 4];
function dummyAsyncCall(token, callback) {
token = token || 0;
setTimeout(function() {
callback({
dummyDataPart: dummyData[token],
token: (typeof (dummyData[token]) == 'undefined') ? null : (token + 1)
});
});
}
// Here is how you would recursively call it with promises:
function getAllData() {
//data accumulator is sitting within the function so it doesn't pollute the global namespace.
var dataSoFar = [];
function recursiveCall(token, resolve, reject) {
dummyAsyncCall(token, function(data) {
if (data.error) {
reject(data.error);
}
if (!data.token) {
//You don't need to return the resolve/reject result.
resolve(dataSoFar);
} else {
dataSoFar = dataSoFar.concat(data.dummyDataPart);
recursiveCall(data.token, resolve, reject);
}
});
}
return new Promise(function(resolve, reject) {
// Note me passing resolve and reject into the recursive call.
// I like it this way but you can just store them within the closure for
// later use
recursiveCall(null, resolve, reject);
});
}
//Here is the call to the recursive service.
getAllData().then(function(data) {
console.log(data);
});
Fiddle with me
That's because you dont need to return resolve/reject, just call resolve/reject when the recursive call completes. A rough code would look like this
var getEndpoints = function(platformARN, token) {
return new models.sequelize.Promise(function(resolve, reject) {
var params = {
PlatformApplicationArn: platformARNDev
};
if (token != null) {
params['NextToken'] = token;
}
sns.listEndpointsByPlatformApplication(params, function(err, data) {
if (err) {
reject(err);
}
else {
endpoints = endpoints.concat(data.Endpoints); //save to global var
if ('NextToken' in data) {
//call recursively
getEndpoints(platformARN, data.NextToken).then(function () {
resolve(true);
}).catch(function (err) {
reject(err);
});
}
else {
console.log('trying to break out!');
resolve(true);
}
}
});
});
}
(caution: this is just a rough code, may work or may not, but is to give a general idea)
I've added a code snippet below, to support this concept, and it works great, check it out.
i = 0;
$('#output').empty();
function pro() {
return new Promise(function(resolve, reject) {
if (i > 3) {
resolve();
return;
}
window.setTimeout(function() {
console.log(i);
$('#output').append(i).append('<br/>');
i += 1;
pro().then(function() {
resolve()
}).catch(function() {
reject()
});
}, 2000);
});
}
pro().then(function () { $('#output').append("now here"); })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="output"></div>

Promise.promisify is not a function

I wrote JavaScript like this:
var keys=null;
var promise=Promise.promisify(alchemyapi.keywords("url",myUrl,{},function(response) {
var keywords = { url:myUrl, response:JSON.stringify(response,null,4), results:response['keywords'] };
return keywords;
}));
promise.then(
(result)=>{
var keys=result;
console.log(keys);
},
(error)=>console.log(error)
);
I'm using AlchemyAPI and trying to store data I got into my database
How should I do?
You should be able to use Promise to return expected results by removing .promisify which is not a built-in Promise method ; substituting passing keywords to resolve within Promise constructor for return
var keys = null
, promise = new Promise(function(resolve) {
alchemyapi.keywords("url", myUrl, {}, function(response) {
var keywords = {url: myUrl
, response: JSON.stringify(response,null,4)
, results:response['keywords']
};
resolve(keywords);
// error handling ?
})
}).then(function(result) {
keys = result;
console.log(keys)
}, function(err) {
console.log(err)
})
For a more general Promise.promisify function without Bluebird, I ended up writing this:
function promisify(func) {
return function promiseFunc(options) {
return new Promise(function executor(resolve, reject) {
func(options, function cb(err, val) {
if (err) {
return reject(err);
} else {
return resolve(val);
}
});
});
}
}
Hopefully someone else finds this helpful, but in most cases it's probably worth importing Bluebird.

Categories