How to use Promise.all with if statement init - javascript

For last few hours I am trying to make condition inside Promise.all to read images if there is a path for it or to pass a specific value if there is not.
When I use my code results that I get in next .then part is undefined. I checked the values that I am passing, they are not undefined. What can cause the problem?
Here is my code:
readPostImages: (rows) => {
return Promise.all(
rows.map((value) => {
if (value.firstImage != "null") {
return fs.promises.readFile(value.firstImage, {
encoding: "base64",
});
} else {
return Promise.resolve("null");
}
})
);
},
And here is my App.js that return undefined:
.then((result) => {
postModules.readPostImages(result);
})
.then((result) => {
console.log(result);
// return postModules.addImagesToData(rows, result);
})

Related

nodejs express Why not return res?

I want to finish if isBookmark is true
Enter the then below and console.log(1); This works, I hope it doesn't work
checkLecture(addLectureInformation)
.then(() => {
return insertLecture(addLectureInformation);
})
.then((succesInsertLecture) => {
if (true) {
return res.status(200).json(succesInsertLecture);
} else {
return Promise.all([1]);
}
})
.then(num => {
console.log(1);
})
Help
You can't skip steps in your promise chain, but you can move the last then so it is not called if you returned a response already:
checkLecture(addLectureInformation)
.then(() => {
return insertLecture(addLectureInformation);
})
.then((succesInsertLecture) => {
// this should be other condition, because this will be true always and "else" is not even needed/run
if (true) {
return res.status(200).json(succesInsertLecture);
} else {
// Moving the last "then" here, so it is not called is you have sent a response already
return Promise.all([Promise.resolve(1)]) // Promise all expects an array of promises
.then(num => {
console.log(1);
})
}
});

Promise function returns undefined

Help, I'm just trying to learn the promise function. I am confused how to return the promise function value.
static getTrailer(movieId) {
return fetch(`http://api.themoviedb.org/3/movie/${movieId}?api_key=###&append_to_response=videos`)
.then(response => {
return response.json();
})
.then(responseJson => {
if (responseJson.videos.results[0]) {
Promise.resolve(responseJson.videos.results[0].key)
.then(result => {
console.log(result);
return result;
});
} else {
return Promise.reject(`Trailer is not found`);
}
});
}
This is where i tried to get the result
<p>${DataSource.getTrailer(this._movie.id).then(resultKey => {console.log("data is: " + resultKey)})}</p>
But the resultKey always return undefined value. How can i fix this ?
if (responseJson.videos.results[0]) { then you don't return anything, so the promise resolves as undefined.
And why are you even doing anything with Promise.resolve in the first place?
Get rid of the pointless extra promise, and return the value you want to resolve the then with.
.then(responseJson => {
if (responseJson.videos.results[0]) {
const result = responseJson.videos.results[0];
console.log(result);
return result;
} else {
return Promise.reject(`Trailer is not found`);
}
});
To pass data down a promise chain, you need to return (either explicitly, or implicitly from an arrow function)
Here it is, nice and simple;
static getTrailer(movieId) {
return fetch(`http://api.themoviedb.org/3/movie/${movieId}?api_key=###&append_to_response=videos`)
.then(response => response.json())
.then(responseJson => responseJson.videos.results[0].key) // an error thrown for whatever reason, will caught below.
.catch(error => {
// an error thrown by any of the three preceding stages will end up here
throw new Error(`Trailer is not found`); // throwing is less expensive than returning Promise.reject()
});
}
You don't need to use promise for the get the key again.
static getTrailer(movieId) {
return fetch(`http://api.themoviedb.org/3/movie/${movieId}?api_key=###&append_to_response=videos`)
.then(response => {
return response.json();
})
.then(responseJson => {
if (responseJson.videos.results[0]) {
result = responseJson.videos.results[0].key;
console.log(result);
return result;
} else {
return Promise.reject(`Trailer is not found`);
}
});
}

Return deleted docs data returns undefined

I am using Google Cloud Function, but since it runs on a older version of Node, I can not use this answer anymore. I want a function that will batch delete all the documents in a collection and returns the data from it. This is my attempt:
function deleteCollectionAndReturnResults(db, collectionRef, batchSize) {
var query = collectionRef.limit(batchSize);
return deleteQueryBatch(db, query, batchSize, []);
}
function deleteQueryBatch(db, query, batchSize, results) {
return query.get().then(snapshot => {
if (snapshot.size == 0) return 0;
var batch = db.batch();
snapshot.docs.forEach(doc => {
if (doc.exists) {results.push(doc);}
batch.delete(doc.ref);
});
return batch.commit().then(() => snapshot.size);
}).then(function(numDeleted) {
if (numDeleted >= batchSize) {
return deleteQueryBatch(db, query, batchSize, results);
}else{
return results
}
});
}
But when I run it like this:
exports.tester = functions.firestore.document('x/{x}').onCreate(event => {
deleteCollectionAndReturnResults(db, db.collection("x"), 100).then(docs => {
console.log(docs)
})
})
This is my output:
Is there something wrong why I do get the 'function returned undefined'?
Your tester function doesn't return anything. Instead, it should return a promise that's resolved when all the work is complete. It looks like you've simply forgotten to return the promise returned by deleteCollectionAndReturnResults:
exports.tester = functions.firestore.document('x/{x}').onCreate(event => {
return deleteCollectionAndReturnResults(db, db.collection("x"), 100).then(docs => {
console.log(docs)
})
})

Export function with promise, wait for response

I'm calling a function inside a then statement, and that function has to wait for an event to fire, but my initial function is returning undefined almost immediately:
// call.js
const dialogflow = require('./dialogflow')
module.exports = {
receive: functions.https.onRequest((request, response) => {
...
let respondToUser = getUserId
.then((uid) => {
payload.uid = uid
dialogflow.handleIncoming(payload).then((result) => {
console.log(result)
})
})
.then((result) => {
console.log(result)
response.end()
})
...
}
}
// dialogflow.js
module.exports = {
handleIncoming: (payload) => {
...
let df = dialogflow.textRequest(message.message, {
sessionId: payload.from
})
.on('response', (response) => {
return response.result.fulfillment.speech
})
.on('error', (error) => {
return 'That\'s an error on my end. Try again later!'
})
.end()
}
}
The goal is to call dialogflow.handleIncoming(payload) from call.js, wait for it to return some text, and then continue. But no matter how I have structured it, receive just keeps blowing through it and dialogflow.handleIncoming(payload) ends up undefined.
I've tried using a promise on df with no success, and I can't figure out how to make respondToUser wait for a full response from handleIncoming. Everything else is working so I'm only including relevant code.
This is using api.ai (dialogflow), but in cloud functions in Firebase if that helps. Appreciate any help!
Problem is dialogflow.handleIncoming(payload) is not structured for async. Try this:
// dialogflow.js
exports.handleIncoming = (payload) =>
new Promise((resolve, reject) => {
...
let df = dialogflow.textRequest(message.message, {
sessionId: payload.from
})
.on('response', (response) => {
resolve(response.result.fulfillment.speech)
})
.on('error', (error) => {
reject ('That\'s an error on my end. Try again later!')
})
.end()
}
Your receive function isn't waiting for dialogflow.handleIncoming(payload) to complete. The then function that contains it doesn't have a return statement, so it's returning undefined rather than returning the result of dialogflow.handleIncoming (which is what you want).
let respondToUser = getUserId
.then((uid) => {
payload.uid = uid
return dialogflow.handleIncoming(payload)
})
.then((result) => {
console.log(result)
response.end()
})
The next then statement will contain the response from diagflow.handleIncoming.

In Node, how do I request JSON from multiple URLs using promises?

Please forgive the fairly case-specific question, though I think the general end goal could be of use to other people.
Goal: Populate a MongoDB with data requested from multiple JSON API URLs.
Short question: So far I've had some success with request-promise, which uses Bluebird:
var rp = require('request-promise');
var options = {
uri: 'http://www.bbc.co.uk/programmes/b006qsq5.json',
headers: {
'User-Agent': 'Request-Promise'
},
json: true
};
rp(options)
.then(function (body) {
// Mongoose allows us query db for existing PID and upsert
var query = {pid: body.programme.pid},
update = {
name: body.programme.title,
pid: body.programme.pid,
desc: body.programme.short_synopsis
},
options = { upsert: true, new: true };
// Find the document
Programme.findOneAndUpdate(query, update, options, function(err, result) {
if (err) return res.send(500, { error: err });
return res.send("succesfully saved");
});
})
.catch(function (err) {
return res.send(err);
})
But how do I loop over an array of URLs, without the program failing if any of the promises are rejected?
Something like this for example, using Bluebird, fails if any of the URLs errors.
const urls = ['http://google.be', 'http://google.uk']
Promise.map(urls, rp)
.map((htmlOnePage, index) => {
return htmlOnePage;
})
.then(console.log)
.catch((e) => console.log('We encountered an error' + e));
As I want to write to the DB with successful requests, and ignore those that might not be responding right then, I need something that skips over rejected promises, which .all does not do.
Long question:
I've been reading up about promises all day and it's making my head hurt! But I've found some good resources, such as https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html, which mentions the use of a Promise factory. Would this work for my case? I initially thought I should make each request, process the result and add it to the DB, then move on to the next request; but having seen .all I thought I should do all the requests, save the results in an array and loop over that with my DB saving function.
Should I even be using Promises for this? Maybe I should just make use of something like async.js and run my requests in series.
Thanks very much for any help or ideas.
But how do I loop over an array of URLs, without the program failing if any of the promises are rejected?
if you return a value from .catch other than a rejected promise, you will return a resolved promise
So, your .then for each individual request could return an object like
{
success: true,
result: whateverTheResultIs
}
and your catch returns
{
success: false,
error: whateverTheErrorIs
}
Really you don't NEED the success property, it's a convenience though
So the code would be - assuming process(url) returns a Promise
Promise.map(urls, url =>
process(url)
.then(result => ({result, success:true}))
.catch(error => ({error, success:false}))
)
.then(results => {
let succeeded = results.filter(result => result.success).map(result => result.result);
let failed = results.filter(result => !result.success).map(result => result.error);
});
Or, in ES5
Promise.map(urls, function (url) {
return process(url).then(function (result) {
return { result: result, success: true };
}).catch(function (error) {
return { error: error, success: false };
});
}).then(function (results) {
var succeeded = results.filter(function (result) {
return result.success;
}).map(function (result) {
return result.result;
});
var failed = results.filter(function (result) {
return !result.success;
}).map(function (result) {
return result.error;
});
});
I don't know if this fit your case, but I think You can use a counter to check when all promises has returned, regardless of the fact that each one has been resolved or rejected
var heroes = [
'Superman',
'Batman',
'Spiderman',
'Capitan America',
'Ironman',
];
function getHero(hero) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return Math.round(Math.random()) ? resolve(hero + ' lives') : reject(hero + ' dead');
}, Math.random() * 3000)
})
}
function checkHeroes() {
var checked = heroes.length;
heroes.forEach((hero) => {
getHero(hero)
.then((res) => {
checked --;
console.log(res);
if (!checked) done();
})
.catch((err) => {
checked --;
console.log(err);
if (!checked) done();
});
})
}
function done() {
console.log('All heroes checked');
}
checkHeroes();
I think your issue is less about the bluebird api than structuring your promise chain.
const reducePropsToRequests = (props) => Promise.resolve(Object
.keys(props)
.reduce((acc, key) => {
acc[key] = request(sources[key]);
return acc;
}, {}));
const hashToCollection = (hash) => Promise.resolve(Object
.keys(hash)
.reduce((acc, k) => {
return [...acc, {source: k, data: hash[k]}];
}, []));
const fetchFromSources = (sources) => Promise.props(sources);
const findSeveralAndUpdate = (results) => Promise
.each(results.map(obj => {
// you have access to original {a: 'site.com'}
// here, so use that 'a' prop to your advantage by abstracting out
// your db config somewhere outside your service
return Programme.findOneAndUpdate(someConfig[obj.source], obj.data);
}))
const requestFromSeveralAndUpdate = (sources) => reducePropsToRequests(sources)
.then(fetchFromSources)
.then(hashToCollection)
.then(findSeveralAndUpdate)
.catch(/* some err handler */);
requestFromSeveralAndUpdate({ a: 'site.com', b: 'site.net' });
I'd just use request and write my own promise with try catch inside that only resolves. Pseudo example below
var request = require('request')
var urls = ['http://sample1.com/json', 'http://sample2.com/json']
var processUrl = (url) => {
return new Promise((resolve,reject)=> {
var result;
try {
var myRequest = {
uri: url,
method: 'GET',
header: {...}
};
request(option, (res,body,err)=> {
if(err) {
result = err;
return;
}
result = body;
})
}
catch(e) {
result = e;
}
finally {
resolve(result)
}
})
}

Categories

Resources