如何在JavaScript中等待meteor调用响应,然后执行其他语句?

dxpyg8gm  于 2023-08-02  发布在  Java
关注(0)|答案(4)|浏览(113)

我在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之前执行。那么,有没有什么方法可以实现这一点,并等待流星调用完成执行下一个指令?

rseugnpd

rseugnpd1#

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

选项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)使代码看起来像是同步的,但执行的本质仍然是异步的。这与Promises的工作方式或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


为了进一步解释,我将引用以下文档:
在客户端,如果你没有传递回调函数,并且你不在存根中,call将返回undefined,你将无法获得方法的返回值。这是因为客户端没有纤程,所以实际上没有任何方法可以阻止方法的远程执行。
摘要:Meteor.wrapAsync不能与Meteor.call一起使用。

选项C -一个方法绑定

与其尝试创建同步的meteor调用序列,还可以将所有参数和逻辑提供给单个服务器方法,该方法返回一个保留所有返回值的对象:

  • 客户端.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,
    }
  }
})


这将创建一个顺序执行(通过遵循您在问题中提供的顺序逻辑),并在绑定的对象中返回所有结果。
优点:按需顺序,一个请求-所有结果一个额外的方法要测试,可以引入方法之间的紧密耦合,返回对象可以变得很大,复杂到clinet的解析要求:对方法设计的良好感觉
如果我有其他选择,我会把它们添加到这篇文章中。

00jrzges

00jrzges2#

方法之一是稍微重新组织代码。

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");
  });
});

字符串

nom7f22z

nom7f22z3#

您必须使用promise作为未来纤维的示例
在服务器上

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 for ref https://github.com/jagi/meteor-astronomy/issues/562

llmtgqce

llmtgqce4#

抱歉,我不喜欢这些解决方案。如何将Meteor.call回调转换为promise?

const meteorPromiseCall = (method: string, ...args: any[]) =>
  new Promise((resolve, reject) => {
    Meteor.call(method, ...args, (err: any, res: any) => {
      if (err) reject(err);
      else resolve(res);
    });
  });

字符串
和使用示例:

const Dashboards = () => {

  const [data, setData] = useState(null);
  
  const readData = async () => {
    // Waiting to all Meteor.calls
    const res = await Promise.all([
      meteorPromiseCall(
        "reports.activitiesReport",
        DateTime.now().startOf("day").minus({ day: 30 }).toJSDate(),
        DateTime.now().startOf("day").toJSDate(),
      ),
      meteorPromiseCall(
        "reports.activitiesReport2",
        DateTime.now().startOf("day").minus({ day: 30 }).toJSDate(),
        DateTime.now().startOf("day").toJSDate(),
      ),
      meteorPromiseCall(
        "reports.activitiesReport3",
        DateTime.now().startOf("day").minus({ day: 30 }).toJSDate(),
        DateTime.now().startOf("day").toJSDate(),
      ),
    ]);
    setData(res[0]);
  };

  useEffect(() => {
    readData();
  }, []);

  if (!data) return <div>Loading...</div>;

  return (...)

相关问题