Yes - this sort of thing is supported:
Meteor.methods({
async someMethod(x, y) {
const a = await someAsyncFunction(x);
return await someOtherAsyncFunction(a, y);
}
});
Yes - this sort of thing is supported:
Meteor.methods({
async someMethod(x, y) {
const a = await someAsyncFunction(x);
return await someOtherAsyncFunction(a, y);
}
});
@robfallows have you actually done that? Based on what @ilacyero reports:
ā¦ I canāt use await inside a meteor method, because I should define the method as async and it generates error ā¦
Yes. It works exactly as it should when called from the client (the Promise is resolved before the result is sent back over the wire).
When I was playing with this a few months back I got unexpected results (the Promise itself) when calling an async method from within the same server code (not something I normally do).
Hm, so given a methods-calling-methods situation, eventually some of those methods will be getting called form the server as well. And then it might (based on what I understand from your experience) cause issues, right?
Perhaps. I found that behaviour, but I havenāt revisited those tests for quite a while, so it may be fixed now. I should probably take another look. I was putting a repro together for @benjamn, but got sidetracked and didnāt finish it.
Hm, thank you, though, I guess Iāll need to find that out for myself sooner or later and Iāll sure do post back here if/when I do.
Hmm, interestingly what I did which works is I just returned the promise in the method and then in the Meteor call all I did was await, seems a lot simpler than what youāre doing here and works for me but maybe thereās a reason why I shouldnāt do this?
I just trial and errored here, maybe this is not the right approach
Letās say you have a call on the client like following
Meteor.call('myMethod', (err, res) => alert(res))
with an async function you can define the method like that:
const myPromise = () => new Promise((resolve, reject) => resolve('hi'))
Meteor.methods({
myMethod: async () => {
const msg = await myPromise()
return msg
}
})
This essentially allows to write your code in a āsynchronousā style, while still staying async by await
ing promises.
sorry @robfallows but it doesnāt. Async/Await stopped working a few months ago (this summer?). Now I have to use Promise.await().
It works in NPM modules, but as soon as the async is somewhere near client side code, it stops working.
I opened a few topics and filed a github issue, but I got no response.
Do you have a repro? Iāve been using async/await on the client and server without issue (other than in-server method calls as mentioned). Iām currently on 1.4.2.
The important thing to remember is that if you āpromisifyā a Meteor method, the Promise is resolved before the data is sent over the wire to the client. That means that you can, if you wish, continue to use the standard, callback form of Meteor.call
and it will work as it always did.
However, you can āpromisifyā the call. I use something like this for a promised call:
const callWithPromise = (method, myParameters) => {
return new Promise((resolve, reject) => {
Meteor.call(method, myParameters, (err, res) => {
if (err) reject('Something went wrong');
resolve(res);
});
});
}
and then inside an async
function:
const result = await callwithPromise('someMethod', { some: parameter, someOther: parameter });
Hmm, interestingly what I did which works is I just returned the promise in the method and then in the Meteor call all I did was await, seems a lot simpler than what youāre doing here and works for me but maybe thereās a reason why I shouldnāt do this?
I just trial and errored here, maybe this is not the right approach
@robfallows using your example just above, can you show an example of āchainingā promises too?
Chaining async calls using promises to me is the real value here.
Hmm. Do you have a repo with this approach? Iāve just tried what (I think) you said and it doesnāt work in the way you explained.
const result = await Meteor.call('someMethod');
I always get undefined
: the method is called (so something happens on the server), but there is no Promise to await, so the call completes without waiting.Using await
makes chaining Promises almost as simple as using sync-style coding on the server. In principle I would take something like that callWithPromise
and just use multiple calls:
const thing = await callWithPromise('methodA'), {} );
const factor = await callWithPromise('methodB', { item: thing } );
const result = await callWithPromise('methodC', { item: thing, factor } );
The only āgotchasā you need to be aware of are:
await
inside an async
function. However, you can do funky things like Template.bob.onCreated(async function() {...
which makes your entire onCreated
async.await
chain out of your async
function and back into your ānormalā code. In Meteor you can do this easily by making use of ReactiveVar
s.So, in Blaze, you could do something like:
Template.bob.onCreated(async function() {
this.result = new ReactiveVar();
const thing = await callWithPromise('methodA'), {} );
const factor = await callWithPromise('methodB', { item: thing } );
this.result.set(await callWithPromise('methodC', { item: thing, factor } ));
}
Template.bob.helpers({
getResult() {
return Template.instance().result.get();
}
});
Thanks rob. But you canāt use the .then syntax somehow?
let calculate = function (value) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value + 1);
}, 0);
});
};
calculate(1)
.then(calculate)
.then(result => result + 1)
.then(calculate)
.then(verify);
function verify(result) {
expect(result).toBe(5);
done();
};
Yes. Theyāre standard Promises (at least insofar as any of the plethora of Promises are standard).
I tried this but Iām not getting the result from the client via console.log
, the server is fine though.
export const useProfileAddress = new ValidatedMethod({
name: 'cart.useProfileAddress',
mixins: [CallPromiseMixin],
validate: new SimpleSchema({
}).validator(),
run(args) {
return (async function() {
try {
const storeId = await getClosestStore.callPromise()
console.info('storeId', storeId) // This part returns something on the Server but it's undefined on the client.
} catch (e) {
console.log(e.message);
}
}())
}
})
export const getClosestStore = new ValidatedMethod({
name: 'store.getClosest',
mixins: [CallPromiseMixin],
validate: new SimpleSchema({
}).validator(),
run(args) {
const store = Store.findOne() // Could it be this?
return store._id
}
})
Am I missing something? Or should I enclose all my method in Meteor.isServer
?
Try this:
export const useProfileAddress = new ValidatedMethod({
name: 'cart.useProfileAddress',
mixins: [CallPromiseMixin],
validate: new SimpleSchema({
}).validator(),
async run(args) {
try {
const storeId = await getClosestStore.callPromise();
console.info('storeId', storeId); // This part returns something on the Server but it's undefined on the client.
return storeId;
} catch (e) {
console.log(e.message);
}
},
});
Thank you @robfallows that lessened my lines of code but Iām still not getting the storeId
from the browser console. So Iāve enclosed my code in Meteor.isServer
to inhibit the error. Could it be because the method is trying to get it from minimongo
and not from the Mongo
since it was simulated on the client?
Particularly this line on my getClosestStore
method?
const store = Store.findOne()
return store._id