【问题标题】:Clean design for centralized navigation?集中导航的简洁设计?
【发布时间】:2015-08-21 13:26:27
【问题描述】:

上下文

单页/ajax 网页应用

基本代码结构

LocationManager(负责更新浏览器哈希并将应用程序位置切换到不同的磁贴)

页面/磁贴流

基本信息>家庭信息>车辆信息>购买选项>查看订单>输入付款并提交

问题

当用户从“购买选项”导航到“查看订单”时,会进行长时间(5-8 秒)的服务调用来计算订单详细信息。在呼叫解决后,回调旨在将用户导航到“查看订单”页面。问题是,如果用户在此期间点击返回并返回家庭信息,一旦呼叫解决,他们将被“自动”带到查看订单。非常尴尬的用户体验。

限制

取消通话不是一种选择。需要一个解决方案来处理导航。

当前提议的实施

在调用 calculateOrder 之前保存“currentLocation”。 将回调中的“currentLocation”作为expectStartingPoint 传递给setLocation 方法。 setLocation 方法里面if(intendedStartingPoint === Locationmanager.currentLocation) {//Navigate}

总而言之,如果用户在通话过程中更改了位置,那么在通话解决后,我们将不会导航,因为此时用户不希望导航到 Review Order。

这行得通,对吧?

渔获

我们在应用程序中有很多地方在回调中调用 setLocation 以进行长时间运行的调用。这意味着我将不得不使用一个新参数--expectedStartingPoint 来更新所有的 setLocation 调用。虽然这对我来说很有意义,但它似乎确实有可能变得有点混乱。

关于如何清理和集中它的任何想法?

【问题讨论】:

  • 将 setLocation 调用包装在一个专门的函数中,将其提供给 Review Order 回调,并使该专门的函数也以一个预期的起始点作为参数并处理预期的起始点逻辑?
  • 在呼叫返回之前禁用后退按钮(或任何操作)怎么样?否则,只需在呼叫返回时检查您当前的位置,并仅在正确的磁贴上进行重定向。 (注意:在这种情况下,仍然可能存在用户返回,修改一些数据,然后返回到正确的磁贴而不重新启动调用的问题,导致在没有保存/验证新数据的情况下被重定向,所以你应该在最少自动重新启动数据更改调用,但简单地取消导航/数据更改调用会更理想。)
  • @SzabolcsPáll 无法从网站内“禁用”浏览器按钮。您提出的解决方案是我在问题中概述的。
  • 然后@Soggiorno 的建议似乎是正确的方法,但我真的不明白完成可能需要重复的呼叫的意义。关于浏览器后退按钮,您还可以暂停根据您的 URL 更改磁贴的功能,直到调用返回,从而阻止该导航。
  • 请删除java标签(如果我理解正确的话)

标签: javascript asynchronous navigation code-structure


【解决方案1】:

因此,现在用户可以单击“购买选项”页面上的“计算”按钮。然后显示某种加载指示器(希望如此) 并向服务器发送一个异步请求,并在延续中附加了setLocation('ReviewOrder')。应用程序中有很多地方使用这种模式。

存在意外(从用户的角度)重定向的问题,因为使用这种方法,服务器数据检索和 UI 导航是耦合的。想到的一个解决方案是将它们解耦并删除 setLocation 调用 从所有长期运行的请求继续。它可以通过以下方式工作。

当用户单击“计算”按钮时,您会启动一个异步请求,同时立即导航到 Review Order 页面(这从 UX 的角度来看很重要,因为用户现在清楚地了解计算按钮导航到查看订单)。在 Review Order 页面上,显示一个加载指示器,上面写着“请稍候,还剩大约 10 秒...”当请求完成时,隐藏加载指示器并显示数据。

通过这种方式,您的用户将获得一致的用户体验,他们知道每当他们点击应用程序中的按钮时都会发生相同的事情(他们导航到视图),并且不会出现令人惊讶的自动重定向。

【讨论】:

    【解决方案2】:

    鉴于您无法阻止用户在图块之间导航,通知她计算延迟并不能解决整个问题。您可以告诉用户预计完成的时间,您可以显示进度条,并且您可以立即将她带到 Review Order 磁贴以等待结果,但如果她导航离开磁贴,您将留下您的原来的问题。

    如果用户在获得所有这些信息后选择离开,她一定是有意识地决定中断程序。将她送回审查订单将是糟糕的用户体验。现在呢?

    您非常合理地建议使用calculateOrder 发送的回调函数应该将intendedStartingPoint 参数传递给setLocation。您担心这会要求您修改对setLocation 的每次调用以适应新参数。不用担心,JavaScript 提供了一种巧妙的方法来解决这个难题。

    您可以在不修改现有调用的情况下向setLocation 添加新参数。这仅仅要求intendedStartingPointsetLocation 的参数列表中的最后一个参数。那么你的新版setLocation可以检查intendedStartingPoint的值,看是不是undefined

    如果intendedStartingPointundefined,您知道setLocation 正在接收一个旧呼叫,即未通过intendedStartingPoint 的呼叫。在这些情况下,您将忽略intendedStartingPoint 并像以前一样继续。否则,您将intendedStartingPoint 与当前位置进行比较,并根据比较结果进行操作。

    更好的方法是使新参数不是intendedStartingPoint,而是一个名为options 的对象,其中包含intendedStartingPoint 作为其属性之一。如果将来需要,这允许您将更多可选值传递给setLocation

    setLocation 的新行为非常简单。在设置新位置之前,请检查intendedStartingPoint 是否等于当前位置。如果是,您不必做任何事情,因为用户已经在她打算去的地方。但如果intendedStartingPoint 与当前位置不同,则用户已导航离开,因此您可以执行以下操作:

    if (LocationManager.currentLocation !== options.intendedStartingPoint) {
      // Tell the user that the calculation has finished.
      // Ask her if she wants to return to Review Order now.
    }
    

    【讨论】:

      【解决方案3】:

      首先,通过异步调用计算订单详细信息,并通过 javascript 向最终用户显示/模拟进度条。

      第二件事:不要在服务回调函数中强制打开ReviewOrder tile。当服务完成计算时,您的回调函数会检查当前磁贴,如果不是ReviewOrder 磁贴,则将计算的信息存储在 Session 或 Local Storage 中。

      当用户浏览ReviewOrder 磁贴时,将来自用户的订单详细信息与存储的订单详细信息(例如通过散列函数)进行比较。

      如果用户订单详情和存储订单详情的hashcode相同,则显示已保存订单信息,否则再次调用服务。

      重要提示:为防止订单伪造,请考虑以下方式:

      在服务器上计算订单详细信息后,生成唯一的订单 ID,并将其返回给用户。然后将计算出的订单详细信息与此 ID 一起存储在服务器数据库中。如果用户没有更改订单详细信息,您的脚本将仅将此订单 ID 发布到服务器作为标志,该订单已被接受。然后读取您的数据库并按此 ID 处理订单。

      如果订单未完成,则使用计划任务,从未完成的订单(例如 - 24 小时前计算但仍未完成的订单)中清理您的数据库。

      【讨论】:

        【解决方案4】:

        首先,如果用户能够返回并更改之前页面上输入的任何信息,则必须使任何待处理的服务调用无效。如果基于过时信息的服务调用返回,则必须将其丢弃。

        这意味着,if(intendedStartingPoint === Locationmanager.currentLocation) {//Navigate} 是不够的。您必须执行类似if(intendedStartingPoint === Locationmanager.currentLocation && /* no information altered in the meantime*/) {//Navigate} 的操作。

        现在是您的设计问题:如果没有任何具体代码,构建它有点困难,但您可以执行以下操作:

        • 提供在LocationManager 中注册和管理长时间运行的调用的方法
        • 应该始终使用LocationManager 注册长时间运行的呼叫
        • LocationManager 应确保同一时刻最多有一个长时间运行的呼叫处于活动状态
        • 如果发生任何位置变化,所有(或一个活动的)长时间运行的调用都必须失效
        • 长时间运行的调用的回调应检查它是否已失效,并且仅在这种情况下进行导航。 LocationManager 可以统一处理所有回调。
        • 新的长时间运行的呼叫可以替换/使已运行的呼叫无效或被拒绝,如您所愿。

        我希望这对您的具体情况有意义。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-10
          • 2019-04-11
          • 1970-01-01
          • 2023-03-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多