如何等待 meteor call 响应,然后执行 javascript 中的其他语句?

How to wait for meteor call response and then execute other statements in javascript?

我在 meteor 的客户端事件中有两个 meteor 调用,我想一个接一个地执行。但是当我调试时,流程并没有按照我想要的方式进行。

client.js

Meteor.call('methodCall',param1,param2,param3,function (error, result) {
    if (error) 
        console.log(error.reason);

    Session.set("xyz",result);
});

var abc=Session.get("xyz");

Meteor.call('methodCall',abc,param2,param3,function (error, result) {
    if (error) 
        console.log(error.reason);

    console.log("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() 不会成功执行,因为第 3 步在第 2 步之前执行时第 1 个参数没有任何值。那么我有什么办法可以实现这个并等待流星调用完成执行下一条指令?

其中一种方法是稍微重组您的代码。

Meteor.call('methodCall',param1,param2,param3,function (error, result) 
{
  if (error) console.log(error.reason);
  Session.set("xyz",result);
  var abc=Session.get("xyz");
  Meteor.call('methodCall',abc,param2,param3,function (error, result) 
  {
    if (error) console.log(error.reason);
    console.log("result: "+result);
    Session.set("cdf",result);
    var pqr=Session.get("cdf");
  });
});

我已经对这种情况的各种选择进行了一些研究,因为这里的其他一些人可能也已经遇到过这种情况。

选项 A - 客户端中的嵌套调用

第一个也是最明显的一个是进行嵌套调用。这意味着在回调中收到结果后调用下一个函数。

// level 1
Meteor.call('methodCall', param1, param2, param3, function (error, result) {
    // level 2
    if (error) console.log(error.reason);

    Session.set("xyz",result);

    Meteor.call('methodCall',result, param2, param3, function (error, result) {
        // level 3...
        if (error) console.log(error.reason);

        console.log("result: "+result);
        Session.set("cdf",result);
    }); 

});

优点: 经典的 js 方式,不需要花哨的新概念,服务器方法坚持简单的逻辑,而客户端死于复杂的工作

缺点:丑陋,会引起混乱,有时难以调试

需要: Template.autorunTracker.autorun 以响应方式捕获来自 Session 的更改。


选项 B - 异步包装

许多人可能已经发现此方法是将异步代码结构化为同步代码的第一选择。

纤程(和使用纤程的 wrapAsync)仅使代码看起来是同步的,但执行的本质仍然是异步的。这与 Promise 的工作方式或 async/await 的工作方式相同。

优点:在单一环境中功能强大

缺点: 不能与 Meteor.call

一起使用

需要:光纤到运行在

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

为了进一步解释,我将引用 documentation:

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一起使用。


选项 C - 以一种方法捆绑

除了尝试创建流星调用的同步序列,您还可以将所有参数和逻辑提供给单个服务器方法,returns 是一个对象,它保留所有 returned 值:

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,
    }
  }
})

这将创建一个顺序执行(通过遵循您在问题中提供的顺序逻辑)并且return它的所有结果都在一个捆绑对象中。

优点:按需顺序,一个请求 - 所有结果 缺点:要测试一个额外的方法,可以在方法之间引入紧密耦合,return 对象会变得大而复杂,无法为客户端解析 要求:良好的方法设计意识

如果我找到其他选项,我会将它们添加到此 post。

你必须使用 promise 例如 future fibers

在服务器上

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.log(err);
  }else{
   console.log(res);
  }
});

link 参考 https://github.com/jagi/meteor-astronomy/issues/562