外部拒绝承诺在Ember

时间:2015-05-13 22:42:20

标签: javascript ember.js promise rsvp-promise

要点:

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

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

最初我们使用Em.RSVP.hash来"捆绑"我们在每条路线的模型钩子中的请求。然而,这会锁定用户界面并最终无法接受。

我们的解决方案是在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数据。

问题:

问题是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并且可能重新考虑慢查询的需要。

谢谢。

1 个答案:

答案 0 :(得分:0)

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

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

didSignOut: false

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

动作:         signOut: - >             @set('didSignOut',true)

return null可以替换为您想要做的任何事情。如果您想要一种集中的方式来处理此事件,您仍然可以通过.then()的第二个参数拒绝承诺,并为其设置RSVP.on("error", ...)处理程序。