У меня есть два вызова метеора в клиентских событиях в метеоре, которые я хочу выполнить один за другим. Но когда я отлаживал поток, не следовал тому пути, который я хотел.
client.js
Meteor.call('methodCall',param1,param2,param3,function (error, result) {
if (error)
console.info(error.reason);
Session.set("xyz",result);
});
var abc=Session.get("xyz");
Meteor.call('methodCall',abc,param2,param3,function (error, result) {
if (error)
console.info(error.reason);
console.info("result: "+result);
Session.set("cdf",result);
});
var pqr=Session.get("cdf");
Как видите, это код, который я хочу запускать в последовательном порядке, то есть один за другим. Но когда я отладил код, я обнаружил, что порядок выполнения:
1. Meteor will be called
3. session.get("xyz") return undefined.
4. Meteor will be called
6. session.get("cdf") return undefined.
2. session.set() will have results as value.
5. session.get() will not have any value.
Второй meteor.call () не будет выполняться успешно, потому что 1-й параметр не будет иметь никакого значения, поскольку шаг 3 выполнялся до шага 2. Итак, есть ли способ добиться этого и дождаться завершения вызова метеора для выполнения следующих инструкций?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Один из способов - немного реорганизовать ваш код.
Meteor.call('methodCall',param1,param2,param3,function (error, result)
{
if (error) console.info(error.reason);
Session.set("xyz",result);
var abc=Session.get("xyz");
Meteor.call('methodCall',abc,param2,param3,function (error, result)
{
if (error) console.info(error.reason);
console.info("result: "+result);
Session.set("cdf",result);
var pqr=Session.get("cdf");
});
});
Я провел некоторое исследование различных вариантов такой ситуации, поскольку некоторые другие здесь тоже могли столкнуться с ней.
Первый и наиболее очевидный - выполнять вложенные вызовы. Это означает вызов следующей функции после получения результата в обратном вызове.
// level 1
Meteor.call('methodCall', param1, param2, param3, function (error, result) {
// level 2
if (error) console.info(error.reason);
Session.set("xyz",result);
Meteor.call('methodCall',result, param2, param3, function (error, result) {
// level 3...
if (error) console.info(error.reason);
console.info("result: "+result);
Session.set("cdf",result);
});
});
Плюсы: классический способ js, не требуются новые причудливые концепции, серверные методы придерживаются простой логики, в то время как клиент умирает от сложной работы
Минусы: некрасивый, может вызвать путаницу и иногда трудно отладить
Требует:Template.autorun или Tracker.autorun, чтобы реагировать на изменения из Session.
Многие, возможно, уже сочли этот метод лучшим выбором для структурирования асинхронного кода в код синхронизации.
Волокна (и wrapAsync, использующие волокна) делают код только смотрю для синхронизации, но характер выполнения остается асинхронным. Это работает так же, как работают обещания или как работает async / await.
Плюсы: мощный, когда в одной среде
Минусы: нельзя использовать с Meteor.call
Требует: волокно для запуска
Однако вы не можете легко вызвать метод Meteor, используя эту функцию. Рассмотрим следующий код
const param1 = "param1";
const param2 = "param2";
const param3 = "param3";
const asyncCall = Meteor.wrapAsync(Meteor.call);
const result1 = asyncCall("methodCall", param1, param2, param3);
// result1 will be undefined
Для дальнейшего пояснения я процитирую документация:
On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn’t have fibers, so there is not actually any way it can block on the remote execution of a method.
Резюме: Meteor.wrapAsync нельзя использовать вместе с Meteor.call.
Вместо того, чтобы пытаться создать синхронизированную последовательность метеорных вызовов, вы также можете предоставить все параметры и логику одному серверному методу, который возвращает объект, который хранит все возвращаемые значения:
client.js
const param1 = "param1";
const param2 = "param2";
const param3 = "param3";
Meteor.call('methodCall', param1, param2, param3, function (err, result) {
const xyz = result.xyz;
const cdf = result.cdf;
});
server.js
function _methodCall(p1, p2, p3) {
// ...
return result;
}
Meteor.methods({
'methodCall'(p1, p2, p3) {
const result1 = _methodCall(p1, p2, p3);
const result2 = _methodCall(result1, p2, p3);
return {
xyz: result1,
cdf: result2,
}
}
})
Это создаст последовательное выполнение (следуя последовательной логике, которую вы указали в своем вопросе) и вернет все его результаты в связанном объекте.
Плюсы: последовательно по желанию, один запрос - все результаты Минусы: один дополнительный метод, который нужно протестировать, может привести к тесному взаимодействию между методами, возвращаемые объекты могут стать большими и сложными для синтаксического анализа для клинета. Требуется: хорошее чутье при разработке метода.
Если я найду другие варианты, я добавлю их в этот пост.
Вы должны использовать обещание, например, будущие волокна
на сервере
Meteor.methods({
'methodCall': function(params...){
var future = new Future();
try{
your code...
future.return(result)
catch(e){
future.throw(e)
}finally{
return future.wait();
}
},
})
На клиенте
Meteor.call('methodCall',params...,(err,res)=>{
if (err){
console.info(err);
}else{
console.info(res);
}
});
ссылка на ref https://github.com/jagi/meteor-astronomy/issues/562