【问题标题】:Externaly Rejecting Pending Promises In Ember外部拒绝 Ember 中的未决承诺
【发布时间】:2015-05-13 22:42:19
【问题描述】:

总结:

我们的 Ember 应用遇到了以下情况,正在努力寻找合适的解决方案。

我们正在处理大量数据,因此我们对数据的一些请求相当慢。

最初我们使用 Em.RSVP.hash 将我们的请求“捆绑”在每个路由的模型挂钩中。但是,这会锁定 UI,最终无法接受。

我们的解决方案是在 setupController 钩子中级联请求,如下所示:

setupController: (controller, model)->
    slowRequest1WhichReturnsAPromise().then (data)->
        # Do something with request 1 data

        slowRequest2WhichReturnsAPromise().then (data)->
            # Do something with request 2 data

            slowRequest3WhichReturnsAPromise().then (data)->
                # Do something with request 3 data

这行得通。我们获得即时页面加载,可以首先显示最相关的数据。

我们努力使 Ember 保持最新(撰写本文时为 1.11.3)。我们使用 Ember Data。

问题:

问题在于 UI 已解锁。例如,用户可以注销(并被重定向到登录页面)。请求持续存在并最终完成,弄乱了我们在登录和注销时设置的 csrf 令牌。用户下次尝试登录时会收到 422 错误。

一个更简单的场景是在长时间运行的请求完成之前更改过滤器设置。新请求(通常通过过滤器更改缩小范围)在初始请求之前完成。然后数据会被最终完成的原始请求覆盖。

我们的直接解决方案是尝试杀死未决的承诺,但找不到“现代”的方式来做到这一点。

这行得通:

allPromises: []

setupController: (controller, model)->
    deferredRequest1 = new Em.RSVP.defer()

    # Store all promises
    @get('allPromises').pushObject(deferredRequest1)

    # Fire off request 1
    # Spark up the next stage when request 1 finishes
    deferredRequest1.promise.then ->
        deferredRequest2 = new Em.RSVP.defer()
        @get('allPromises').pushObject(deferredRequest2)

# ... 
actions:
    signOut: ->
        @get('allPromises').forEach (promise)->
            promise.reject('canceled')

上面的内容有点难看,并且为了理解重点而简化了。

Ember Docs 声明“新代码应该使用 RSVP.Promise 构造函数而不是(延迟)”。但是,使用新方法似乎无法做到这一点。

问题:

是否有一种现代方法可以取消待处理的承诺/请求?
有没有更好的方法来拆分我们的页面加载,以便以一种简洁的方式取消待处理的请求?

更新

我最终使用了延迟。它并不漂亮,但在我们重构 UI 并重新考虑对慢查询的需求之前,它会起作用。

谢谢。

【问题讨论】:

  • 是的,有一些支持正确取消的现代承诺库。但是,RSVP 似乎不是其中之一。

标签: javascript ember.js promise rsvp-promise


【解决方案1】:

首先,在您的“工作”解决方案中,您不会在注销期间取消慢查询。您只是拒绝终止承诺链的承诺,因此不会发送更多请求。 (当 signOut 之前的最后一个查询返回时,它仍然可以改变你的 cookie。)

如果您已经可以接受,那么您需要做的是在承诺链中插入signOut-aware检查,以便在用户退出时立即终止。

didSignOut: false

setupController: (controller, model) ->
    slowRequest1WhichReturnsAPromise().then ->
        return null if didSignOut
        slowRequest2WhichReturnsAPromise().then ->
            return null if didSignOut
            slowRequest3WhichReturnsAPromise().then ->
                return null if didSignOut
                // ...

行动: 签出:-> @set('didSignOut', true)

return null 可以替换为您接下来要执行的任何操作。如果你想要一个集中的方式来处理这个事件,你仍然可以通过.then() 的第二个参数拒绝承诺,并为它设置一个RSVP.on("error", ...) 处理程序。

【讨论】:

    猜你喜欢
    • 2014-08-10
    • 2020-03-07
    • 2023-03-26
    • 2021-09-27
    • 2013-06-22
    • 1970-01-01
    • 2019-08-06
    • 2015-11-19
    • 2013-08-08
    相关资源
    最近更新 更多