Does meteor 1.3 return promise in method or do I need package?


#1

Does meteor 1.3 return promise in method or do I need package? (bluebird)

this forum
this link

and that maybe also explains why my code below, returns too fast (not waiting for result)

CLIENT
Meteor.call(‘generateStreamAndApp’,selectedCustomers,templateGuid, function(err, result) {
if (err) {
sAlert.error(err);
console.log(err);
} else {
console.log(‘generateStreamAndApp succes’, result);
sAlert.success('Streams and apps created, and apps have been published into the stream of the customer ');
updateSenseInfo();
}
});

thank you


#2

Methods don’t return promises by default - you have to choose to do so.

Can we see your method?

BTW: Please wrap your code between triple backticks on separate lines:

```
like
this
```

#3

Hi Rob,
thanks for helping out. yeah, sorry that did not work yesterday (the code highlighting)

This is my code SERVER SIDE

function deleteStream (guid) {
	return HTTP.call( 'DELETE', 'http://'+config.host+'/'+config.virtualProxy+'/qrs/stream/'+guid+'?xrfkey='+config.xrfkey, 
	{
		headers: {
			'hdr-usr' : config.headerValue,
			'X-Qlik-xrfkey': config.xrfkey
		}
	}, function( error, response ) {
		if ( error ) {
			console.error( error );
			throw new Meteor.Error('error stream delete', error)
		} else {
			console.log( response );
			return response;
		}
	});
};

function createStream (name) {
	console.log('create the stream with name', name);
	var myPromise = qrs.post('/qrs/stream', null,  {"name": name})
	.catch(err => {
		console.log(err);
		throw new Meteor.Error(err)
	})
	return myPromise
};

function getStreams () {
	return qrs.get('/qrs/stream/full');
};

Meteor.methods({  
	generateStreamAndApp (customers) {
		check(customers, Array);
		return generateStreamAndApp(customers);
	},
	getApps () {
		return new Promise((resolve, reject) => {
			qsocks.Connect(engineConfig)
			.then(function(global) {
				global.getDocList().then(function(docList) {
					resolve(docList) ;
				});
			})
		})
		.catch(err => {
			throw new Meteor.Error(err)
		})
	},
	copyApp (guid, name) {
		check(guid, String);
		check(name, String);
		return copyApp(guid,name);
	},
	deleteApp (guid) {
		check(guid, String);
		return deleteApp(guid);
	},
	deleteStream (guid) {
		check(guid, String);
		return deleteStream(guid);
	},
	countApps(){
		return qrs.get('/qrs/app/count');
	},
	countStreams(){
		return qrs.get('/qrs/stream/count');
	},
	createStream (name) {
		return createStream(name);
	},
	getStreams () {
		return getStreams();
	},
	getSecurityRules () {
		return getSecurityRules();
	},
	// updateAppsCollection(){
	// 	console.log('Method: update the local mongoDB with fresh data from Qlik Sense');

This is my code on the client

Template.body.events({
  'submit .new-customer'(event) {
    // Prevent default browser form submit
    event.preventDefault();
    // Get value from form element
    const target = event.target;
    const customerName = target.text.value;
    // Insert a task into the collection
    Customers.insert({
      name: customerName,
      createdAt: new Date(), // current time
    });
    // Clear form
    target.text.value = '';
  },
  'click .generateStreamAndApp'() {
    console.log('click event generateStreamAndApp');
    
    var selectedCustomers = Customers.find({checked: true}).fetch();
    // var selectedCustomers = Customers.find().fetch();
    console.log('get customers from database, and pass them to the generateStreamAndApp method', selectedCustomers);
    var templateGuid = '893f8063-2387-4bc3-90f0-d672e8a467d3';

    Meteor.call('generateStreamAndApp',selectedCustomers,templateGuid, function(err, result) {
      if (err) {
        sAlert.error(err);
        console.log(err);
      } else  {
        console.log('generateStreamAndApp succes', result);
        sAlert.success('Streams and apps created, and apps have been published into the stream of the customer ');
        updateSenseInfo();
      }
    });
  },

#4

So, in order to get it to work do I need to
Use the bluebird package
and

Wat I don’t understand yet of the above is
why do we need an IFFY and can I use bluebird in stead of the deanius package?

And how where can I use the value of result, how does it prevent I can use it before it is ready? (sorry I do need to see the video, but sometimes I don;t really understand why people post half examples…)

If i use npm bluebird, I get this issue…

thank you


#5

I am only just starting to learn how to use the promises but can help a little here. Meteor 1.3 includes promise support in the ecmascript package which is usually already included in your project. This internal promise support already has the glue to the Fibers package that should eliminate your error. Note the text at http://docs.meteor.com/packages/ecmascript.html#Polyfills that states “Here are three new constructors that are guaranteed to be available when the ecmascript package is installed”. So, try it without using any 3rd party promise package.


#6

Also, a viable shortcut for you might be to use the new mdg:validated-method package in conjunction with the didericis:callpromise-mixin. The README for the callpromise mixin includes a very simple example of calling a validated method with a promise.


#7

Thanks, but the thing is… You need bluebird to manage the number of connections meteor Fires to external api"s…

I need the promise map

with bluebird

Promise.map([1,2,3,4,5], function(id) {
    return DoSomethingAsyncLikeCopyApp(id);
}, { concurrency: 1 })
.then(function() {
    console.log("done");
});

Verstuurd vanaf mijn iPhone


#8

You might then be interested in this change I stumbled on that Ben Newman made to the meteor/promise package a month ago. From the comment, it looks as though the intention was to provide a function (makeCompatible) to wrap any promise library in a manner that gives it support for fibers.

Regrettably, I’ve found no docs yet on how to use it. The only references I’ve found are the makeCompatible function itself and the internal code making use of it in the 1.3.3 beta. The internal code changes to make use of it can be seen in this delta. I think the relevant code is

require("meteor-promise").makeCompatible(
  exports.Promise = require("./common.js").Promise,
  // Allow every Promise callback to run in a Fiber drawn from a pool of
  // reusable Fibers.
  require("fibers")
);

In this example, “./common.js” contains the internal es6 compatible promise library. You’d be replacing that with a reference to the Promise function from bluebird. Of course, I’m sure the above code needs more adjustment but it is the start of a concept.

Also, I’m guessing that other functions in bluebird that go beyond the standard promise functions may need their own wrappers.

Perhaps someone more in the know will chime in and give us some guidance.


#9

thanks, well that is too much pioneering for me. But I thought, ok maybe I have to stick to meteor packages, normally they solve those issue, but I still get the error

[Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.]```

with this package https://atmospherejs.com/jrudio/bluebird

#10

Ok, I removed all the NPM or meteor packages related to promises. And then I added

meteor add promise

Funny, changed nothing in my code, and I don’t get all the timeout errors anymore. Just a normal

FATAL ERROR: JS Allocation failed - process out of memory

Because I don’t throttle my requests yet… --> therefore I needed the bluebird promise.map function in the first place!

I must say it is a lot of work to find out what works, what you see also in these answers here is that you have to go to a lot of undocumented projects.

Question:Is there anyway where I can see which functions meteor.promise offers me? (I need the map function for example, with concurrency support)

apparently not in the meteor.promise package


#11

Core meteor should do, thanks to @benjamn

Following is a crude example, the way I understood it.

//Promise should be available globally if you have ecmascript package (i guess it has dependency to promise package)
import {Promise} from 'meteor/promise';
//npm install request
import request from 'request';
//consider you have a an async function, make it return a Promise
const get = (url) =>{
  return new Promise( (resolve,reject)=>{
    request( url, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        resolve(body)
      }else{
        reject(error)
      }
    });
  });
}


//say you want to really get into generators etc, even thats supported in 1.3
//not a great use case, but drives the point, so a generator returning a promise
//see get3 method call
function *getStar(url){
  yield new Promise( (resolve,reject)=>{
request( url, function (error, response, body) {
  if (!error && response.statusCode == 200) {
    resolve(body)
  }else{
    reject(error)
  }
});
  });
}
Meteor.methods({
  'get1': (url) => {
    check(url,String);
    //from the method, you can just return the promise.
    return get(url);
  },
  'get2': (url)=>{
    check(url,String);
    //this is not a good use case
    //but if you have a use case for async await, 1.3 Meteor supports it
    //without the need for any other packages
    //so instead of async fn() signature, you can do as follows
    return Promise.async(() => {
      return Promise.await(get(url));
    })();
  },
'get3': (url)=>{
  check(url,String);
  //value is a promise in this case,
  return getStar(url).next().value;
}

});

#12

Thanks,

I use this pattern now. The thing that goes wrong is that on the client the callback returns so too fast, id does Not wait till my for loop is fisnished

The callback is fired immediately. But maybe that is because I have a for each loop

For each client
Return function copy something (this returns a promise)
Next

So I thing I have to wrap this in a promise.all statement. But then I miss the promise.map function in the promise implementation that meteor provides. (To throttle the requests to external api)

Verstuurd vanaf mijn iPhone


#13

Something Like this?

with bluebird

Promise.all(
Promise.map([1,2,3,4,5], function(id) {
    return DoSomethingAsyncLikeCopyApp(id);
}, { concurrency: 1 })
.then(function() {
    console.log("done");
}))
.then() // return succes message to meteor method. This must be a normal text object and Not a promise. In this way i dont have to implement special packages for returning meteor promises

Verstuurd vanaf mijn iPhone


#14

Apologies, I am missing the context. The code described above is it your Method (on the server) or calling a method.
Calling a method (from the client), can be the usual meteor signature or you can use promises again. On the server, the return can be a promise object itself.