return value from Promise - meteor

Considering the example:
function returnValue () {
   return somePromise.then (
     function (someThing) {
       return {
         sucess: true,
         data: someThing
       }
     },
     function (someError) {
       return {
         sucess: false,
         data: someError
       }
     }
   )
}
Console.log (returnValue ())
What should I do so that I actually have "someThing" or "someError"? And not a Promise pending?
Just to note ... when I write a code like this within "Meteor.methods" it works exactly as I would like, that is, it returns a value that I return to the client, but outside of "Meteor.methods" or in the client (browser, using or not any framework) the one I have is a Promise pending.

The function passed to .then() returns results asynchronously. The Promise value of the fulfilled Promise will be available as the argument of the passed function. Console.log (returnValue ()), as you noted, logs the Promise itself, not the Promise value. Chain .then() to returnValue() call. Also, Console.log (returnValue ()) should be console.log().
let somePromise = Promise.resolve("abc");
function returnValue () {
return somePromise.then (
function (someThing) {
return {
sucess: true,
data: someThing
}
},
function (someError) {
return {
sucess: false,
data: someError
}
}
)
}
returnValue().then(function(result) {
console.log(result)
})

Related

props in functions not calling the function

I'm trying to fix a problem from the code and don't understand why is not working.
Function:
export const monthlyKpiActions_disp = (threeMonthsBefore, currentDate) => {
console.log('kpppppppppppppppi')
return monthlyKpiActions.fetch({
filter: {
objectId,
interval: threeMonthsBefore + '/' + currentDate,
names: [
'ecostats_fuelusagetotal',
'ecostats_fuelrefmileage',
'ecostats_co2emission',
'tripstats_mileage',
'tripstats_drivingtime',
'optidrive_indicator_8'
].join(',')
},
forceUpdate: true,
resetState: false
})
}
redux
function mapDispatchToProps(dispatch) {
return {
monthlyKpiActions_func: (threeMonthsBefore, currentDate) => dispatch(monthlyKpiActions_disp(threeMonthsBefore, currentDate)),
}
}
calling the function
const currentDate = moment.utc().add(1, 'months').format(dateFormat)
const threeMonthsBefore = moment.utc().subtract(3, 'months').format(dateFormat)
{ () => this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate) }
The problem is that never enters the function, any suggestions?
That's because you never call the action, this line
{ () => this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate) }
Creates a block scope with an anonymous function which internally calls your action, but its never invoked (nor makes any sense in this context).
Just call the action:
this.props.monthlyKpiActions_func(threeMonthsBefore, currentDate)

How do I return the result of a recursive fetch?

I have the first asynchronous function
fetch("https://api.priceapi.com/v2/jobs", {
body: body,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
method: "POST"
}).then((response) => {
return response.json();
}).then((data) => {
return fetchRepeat(data.job_id)
})
And the second recursive asynchronous function.
function fetchRepeat(id){
fetch("https://api.priceapi.com/v2/jobs/"+ id +"/download.json?token=" + priceapisecret.secret)
.then((response) => {
return response.json()
}).then((data) =>{
if(data.status == "finished"){
var bookdata = {
title: data.results[0].content.name,
price: data.results[0].content.price
}
return bookdata;
}
else{
fetchRepeat(id)
}
})
}
I want to be able to access bookdata in the first async function. How do I do that?
In order to talk about a return your fetchRepeat needs to return the promise. It did not so returning undefined was the result. The last then also didn't return the value of the recursion and thus also resolved to undefined.
Here is a working version:
function fetchRepeat(id) {
// return the promise
return fetch(`https://api.priceapi.com/v2/jobs/${id}/download.json?token=${priceapisecret.secret}`)
.then(response => response.json())
.then(({ status, results: [{ content: { name: title, price } }] = [{ content: {} }] }) =>
(status === 'finished' ? { title, price } : fetchRepeat(id))); // return result of recursion
}
Now I let ESLint handle the formatting and since I use airbnb it prefers destructuring. The error in the last then was obvious since ELSint complained about consistent return. I urge you to use a linter and an IDE which enforces a coding style to reduce bugs in your code and make it easier for others to read.

Exception in delivering result of invoking method

I've been testing on http calls with meteor, I used nitrous (because I had no access to my dev laptop during the weekend) and it worked fine.
But when I tried to run from my local pc it returns:
Exception in delivering result of invoking 'getMatch': TypeError:
Cannot read property 'duration' of undefined.
Any ideas of what could be the cause?
Method definition:
Dota = {};
Dota.getMatch = function() {
if (!Meteor.settings.steamToken)
throw new Meteor.Error(500, 'Enter a valid Steam Token in Meteor.settings');
var matchResponse = Meteor.http.get(
"https://api.steampowered.com/IDOTA2Match_570/GetMatchDetails/V001/?",
{
params:{
"match_id": "1305454585",
"key": Meteor.settings.steamToken
}
}
);
if (matchResponse.statusCode === 200) {
return matchResponse.data.result
}
else {
throw new Meteor.Error(500, "getMatch failed with error: "+matchResponse.statusCode);
}
}
Meteor.methods({
'getMatch': function(){
return Dota.getMatch();
}
})
Calling the method:
Meteor.call('getMatch', function(error, result){
var duration = numeral(result.duration).format('00:00:00');
Session.set('duration', duration);
var winner = Meteor.myFunctions.getWinner(result.radiant_win);
Session.set('winner', winner);
});
Template.layout.helpers({
winner: function () {
return Session.get('winner');
},
duration: function () {
return Session.get('duration');
}
});
Found a solution, I changed the location of
Meteor.methods({
'getMatch': function(){
return Dota.getMatch();
}
})
to server/server.js (I had it in packages/dota/dota.js) and now it works! Thanks #user3374348 for helping!

Mongoose pre.save() async middleware not working on record creation

I am using keystone#0.2.32. I would like to change the post category to a tree structure. The below code is running well except when I create a category, it goes into a deadlock:
var keystone = require('keystone'),
Types = keystone.Field.Types;
/**
* PostCategory Model
* ==================
*/
var PostCategory = new keystone.List('PostCategory', {
autokey: { from: 'name', path: 'key', unique: true }
});
PostCategory.add({
name: { type: String, required: true },
parent: { type: Types.Relationship, ref: 'PostCategory' },
parentTree: { type: Types.Relationship, ref: 'PostCategory', many: true }
});
PostCategory.relationship({ ref: 'Post', path: 'categories' });
PostCategory.scanTree = function(item, obj, done) {
if(item.parent){
PostCategory.model.find().where('_id', item.parent).exec(function(err, cats) {
if(cats.length){
obj.parentTree.push(cats[0]);
PostCategory.scanTree(cats[0], obj, done);
}
});
}else{
done();
}
}
PostCategory.schema.pre('save', true, function (next, done) { //Parallel middleware, waiting done to be call
if (this.isModified('parent')) {
this.parentTree = [];
if(this.parent != null){
this.parentTree.push(this.parent);
PostCategory.scanTree(this, this, done);
}else
process.nextTick(done);
}else
process.nextTick(done); //here is deadlock.
next();
});
PostCategory.defaultColumns = 'name, parentTree';
PostCategory.register();
Thanks so much.
As I explained on the issue you logged on Keystone here: https://github.com/keystonejs/keystone/issues/759
This appears to be a reproducible bug in mongoose that prevents middleware from resolving when:
Parallel middleware runs that executes a query, followed by
Serial middleware runs that executes a query
Changing Keystone's autokey middleware to run in parallel mode may cause bugs in other use cases, so cannot be done. The answer is to implement your parentTree middleware in serial mode instead of parallel mode.
Also, some other things I noticed:
There is a bug in your middleware, where the first parent is added to the array twice.
The scanTree method would be better implemented as a method on the schama
You can use the findById method for a simpler parent query
The schema method looks like this:
PostCategory.schema.methods.addParents = function(target, done) {
if (this.parent) {
PostCategory.model.findById(this.parent, function(err, parent) {
if (parent) {
target.parentTree.push(parent.id);
parent.addParents(target, done);
}
});
} else {
done();
}
}
And the fixed middleware looks like this:
PostCategory.schema.pre('save', function(done) {
if (this.isModified('parent')) {
this.parentTree = [];
if (this.parent != null) {
PostCategory.scanTree(this, this, done);
} else {
process.nextTick(done);
}
} else {
process.nextTick(done);
}
});
I think it's a bug of keystone.js. I have changed schemaPlugins.js 104 line
from
this.schema.pre('save', function(next) {
to
this.schema.pre('save', true, function(next, done) {
and change from line 124 to the following,
// if has a value and is unmodified or fixed, don't update it
if ((!modified || autokey.fixed) && this.get(autokey.path)) {
process.nextTick(done);
return next();
}
var newKey = utils.slug(values.join(' ')) || this.id;
if (autokey.unique) {
r = getUniqueKey(this, newKey, done);
next();
return r;
} else {
this.set(autokey.path, newKey);
process.nextTick(done);
return next();
}
It works.

Async call generates " Error: Can't wait without a "fiber", even with _wrapAsync

I've been having a problem using an RSS parser in meteor. It's an async call, so it needs ot be wrapped, however it still doesn't seem to work. I presume this is because the anonymous on('readable' function is outside the fiber, but I can't see how to resolve it.
var FeedParser = Meteor.require('feedparser');
var request = Meteor.require('request');
function getBlog(url, parameter, id){
request(parameter)
.on('error', function (error) {
console.error(error);
})
.pipe(new FeedParser())
.on('error', function (error) {
console.error(error);
})
.on('readable', function () {
var stream = this,
item;
while (item = stream.read()) {
Items.insert(new_item);
}
});
}
var wrappedGetBlog = Meteor._wrapAsync(getBlog);
Meteor.methods({
blog: function (url, parameter, id) {
console.log('parsing blog');
var items = wrappedGetBlog(url, parameter, id);
}
});
Meteor._wrapAsync() expects the wrapped function to return error and result to a callback. Your function, getBlog(), does not do that so _wrapAsync is not the right approach.
I have wrapped that function before but used a Future.
That approach allowed me to call feedparser from a Meteor.method(), which doesn't allow async functions, but you are also trying to do an insert inside the readable event. I think that insert will complain if it is not in a fiber. Maybe like this would also be necessary:
var r = request( parameter );
r.on( 'response' , function(){
var fp = r.pipe( new FeedParser() ); //need feedparser object as variable to pass to bindEnvironment
fp.on('readable', Meteor.bindEnvironment(
function () {
var stream = this,
item;
while (item = stream.read()) {
Items.insert(new_item);
}
}
, function( error ){ console.log( error );}
, fp // variable applied as `this` inside call of first function
));
});
Fibers is another option...
var Fiber = Npm.require( "fibers" );
.on('readable', function () {
var stream = this,
item;
while (item = stream.read()) {
Fiber( function(){
Items.insert(new_item);
Fiber.yield();
}).run();
}
});

Resources