【问题标题】:meteor: how to stop asynchronous call?流星:如何停止异步调用?
【发布时间】:2017-02-21 03:25:57
【问题描述】:

是否可以停止(杀死)异步调用?

在我的应用程序中,我在客户端有类似的东西:

Meteor.call('doCalculation', function(err, result) {
  //do sth with result
});

'doCalculation' 可能需要很长时间(这没关系) 我不希望用户在他/她已经有一个正在运行的通话时开始新通话,我希望允许用户停止当前通话并提交新通话。这样做的正确性如何?

我唯一的想法是使用 mongo 在客户端和服务器之间进行通信。在“doCalculation”函数的某个地方,我可以观察到一些 mongo 文档/集合,并基于此在函数中执行某项操作(例如调用异常)。你有更好的想法吗?

【问题讨论】:

    标签: meteor


    【解决方案1】:

    您可以为此使用semaphore。当semaphore为1时,允许发送请求。当semaphore为0时,不允许发送请求。信号量默认为 1,在发送请求之前,需要将其设置为 0。响应成功后,将 semaphore 设置回 1。

    关于超时:您可以在发送请求后使用setTimeout 使用超时,如下所示:

    if (semaphore) {
        var isTimedOut = false;
        var isSuccess = false;
        semaphore = 0; //No need to use var keyword, as this should be declared outside of this scope
        Meteor.call('doCalculation', function(err, result) {
            isSuccess = true;
            //do sth with result
        });
        setTimeout(function() {
            if (!isSuccess) {
                isTimeout = true;
                //do something else, to handle the time out state
            }
        }, 10000);
    }
    

    【讨论】:

    • 感谢您的回复,但这不是我的问题的答案。我无法设置超时,在这种情况下没有长时间通话。在相同的情况下,通话可能需要几秒钟(或更少)在同一其他几分钟内,两者都可以。我不想强迫用户等待他/她的工作结束(因为我写的长期工作通常是正确的,我不能禁止它)。我确实希望用户能够停止工作。
    • @rmrmg 一旦您的浏览器发送了一个请求,它就会被发送。您无法取消发送它,因为它不再在您控制的计算机上。您唯一能做的就是以这样一种方式实现回调,即它会忽略超时后到达的响应并控制等待限制。这个答案解释了如何做到这一点。
    【解决方案2】:

    这很棘手,因为您通常无法从客户端的角度设置超时。出于一系列架构原因,您不需要这样做。最重要的是,如果您失去网络连接或服务器崩溃(两种情况超时旨在管理),客户端会立即意识到,因为它已断开连接。如果这种情况经常发生,您可以使用Meteor.status().connected

    听起来您正在服务器上运行很长的计算。我的建议是立即返回一个calculationId,然后根据您的计算更新一个带有进度的集合,例如CalculationProgresses.update(calculationId, {$set: {progress: currentProgress}})。然后,您的 UI 可以以最方便的方式反应性地更新进度。

    请注意,当您在服务器上运行长时间的计算时,您需要偶尔“让步”,让其他工作有机会发生。 Meteor 所基于的 Node 如果您不掌握这种让步的概念,那么对于长时间的计算来说是很棘手的。在 Meteor 中,您可以通过更新集合(例如,您的进度集合)轻松地产生。这将解决您在编写应用程序时可能遇到的许多问题。

    【讨论】:

    • 关于您对产量的评论,Fibers 能解决这个问题吗?即在 Fiber 中结束长时间运行的操作会解决产量问题,还是只会在开始时产生一次?我想更好地理解这一点。
    • 您可以为长时间运行的操作创建光纤(Meteor.bindEnvironment 为您执行此操作,Meteor.async 也为您执行此操作)。在MongoCollection::update 中,最终会调用Fiber.yield(),这也是更新集合的原因。确保在方法中调用this.unblock(),以便客户端可以发出更多请求。
    【解决方案3】:

    我认为您需要一个服务器端解决方案。如果您使用客户端解决方案,则不会处理两种情况:

    1. 用户重新加载浏览器
    2. 用户使用 2 个浏览器

    我会创建这些方法:

    1. isCalculationActive() -- 检查用户是否已经激活了计算。在服务器上,您可以将该事实保存在内存中或将其写入数据库。在客户端,如果返回 false,那么您可以继续调用 doCalculation()。如果为真,您可以给用户一个弹出窗口或警报或询问他们是否要取消并继续。

    2. doCalculation() -- 这会取消该用户的所有未完成的计算并开始一个新的计算。

    实现这些后,用户可以重新加载浏览器,而不会影响正在运行的计算或正确的行为。如果他们尝试使用第二个浏览器,一切仍应按预期工作。

    如果您想让用户选择简单地停止作业而不是开始新作业,那么您可以简单地创建:

    1. cancelCalculation() -- 这将取消该用户的任何未完成的计算。

    【讨论】:

      猜你喜欢
      • 2016-07-17
      • 2015-11-18
      • 2020-02-01
      • 2017-05-02
      • 2019-06-01
      • 1970-01-01
      • 2012-12-26
      • 1970-01-01
      • 2021-12-23
      相关资源
      最近更新 更多