Angular ngrx效果:由一个效果发送的动作是否立即由其他效果处理?

Angular ngrx效果:由一个效果发送的动作是否立即由其他效果处理?,angular,ngrx,ngrx-effects,Angular,Ngrx,Ngrx Effects,我有一个有四个ngrx动作的角度(2)应用程序: 开始 减速器未处理(无状态变化) ngrx效应调用异步任务并映射到成功或错误 成功 由减速机加工 ngrx效果图向前进 前进 未经减速机加工 ngrx效果导航到不同的路线 错误 由减速机加工 无效 问题是,捕捉前进的效果似乎先于处理成功的减速器运行 以下是效果代码: @Effect() start$ = this.actions$ .ofType('START') .map(toPayload) .sw

我有一个有四个ngrx动作的角度(2)应用程序:

  • 开始
    • 减速器未处理(无状态变化)
    • ngrx效应调用异步任务并映射到成功或错误
  • 成功
    • 由减速机加工
    • ngrx效果图向前进
  • 前进
    • 未经减速机加工
    • ngrx效果导航到不同的路线
  • 错误
    • 由减速机加工
    • 无效
问题是,捕捉前进的效果似乎先于处理成功的减速器运行

以下是效果代码:

@Effect() start$ = this.actions$
    .ofType('START')
    .map(toPayload)
    .switchMap(input => doAsyncTask(input)
        .map(result => ({type: 'SUCCESS', payload: result}))
        .catch(error => ({type: 'ERROR', payload: error})));

@Effect() success$ = this.actions$
    .ofType('SUCCESS')
    .map(() => ({type: 'ADVANCE'}));

@Effect({dispatch: false}) advance$ = this.actions$
    .ofType('ADVANCE')
    .withLatestFrom(this.store$.select(state => state.route))
    .map(action_route => action_route[1])
    .do(route => this.router.navigate([route.foo.bar]));
我得到的错误是
无法读取null的属性“bar”
。属性
foo
由处理成功的减速器设置

如果我为成功效果添加延迟,一切都会很好地工作:

@Effect() success$ = this.actions$
    .ofType('SUCCESS')
    .delay(1)
    .map(() => ({type: 'ADVANCE'}));
但是不得不加上这个延迟对我来说没有意义

我在所有地方添加了
console.log
语句,输出如下:

  • 成功效应
  • 高级效果(显示route.foo==null)
  • 成功减速机(显示route.foo==something)
  • 错误
  • 我期望成功效果和成功减速器在高级效果之前运行

    我做错什么了吗?

    期望减缩器按照其分派的相同顺序处理操作是否不正确?


    版本:

    • @angular/cli:1.0.0-beta.32.3
    • 节点:7.5.0
    • os:Darwinx64
    • @角度/普通:2.4.7
    • @角度/编译器:2.4.7
    • @角度/核心:2.4.7
    • @角度/形状:2.4.7
    • @angular/http:2.4.7
    • @角度/平台浏览器:2.4.7
    • @角度/平台浏览器动态:2.4.7
    • @角度/路由器:3.4.7
    • @angular/cli:1.0.0-beta.32.3
    • @角度/编译器cli:2.4.7
    • @ngrx/core@1.2.0
    • @ngrx/effects@2.0.0
    • @ngrx/store@2.2.1
    • rxjs:5.1.1

    ngex/effects的目的是在基于redux的环境中充当中间件

    因此,您在这里基本上所做的是将“成功”操作称为“成功”操作,该操作应同时适用于减速机和另一个操作,即中间件。但这是effecs的辅音,它应该拦截动作并自己处理它们,只有在异步处理它分派动作之后

    那么这里发生了什么?您将成功分派到两个不同的地方,一个由减速器处理,另一个由中间件处理。我不确定它是否总是这样,但中间件会在传入操作到达减速机之前拦截它。我认为,如果您对代码稍加修改,它应该可以工作。试着做一些类似的事情:

    @Effect() start$ = this.actions$
        .ofType('START')
        .map(toPayload)
        .switchMap(input => doAsyncTask(input)
            .map(result =>{
                   this.store$.dispatch(
                   {type: 'SUCCESS',
                    payload: result
                    });
                   this.store$.dispatch(
                   {type: 'ADVANCE'})
    
    }
    
            .catch(error => ({type: 'ERROR', payload: error})));
    
    你知道我在这里做什么吗?我已经删除了拦截“成功”的中间件,因此“成功”不会击中减速机。紧接着,它会发送另一个类型为“advance”的动作,在“成功”处理完成后,该动作会击中您的中间件


    希望对你有帮助

    用.concatMap替换开始操作捕获中的.map,并将您的成功地图和行动地图都放在那里,可能会奏效

    @Effect() start$ = this.actions$
        .ofType('START')
        .map(toPayload)
        .switchMap(input => doAsyncTask(input)
            .concatMap(result => {
                return Observable.from([type: 'SUCCESS', payload: result,
                                        type: 'ADVANCE'])
            .catch(error => ({type: 'ERROR', payload: error})));
    

    回答您的结论性问题:

    • 我做错什么了吗
    • 不,我不认为你做错了什么
    • 期望减缩器按照调度操作的相同顺序处理操作是否不正确
    • 这样的顺序似乎是合乎逻辑的,但显然你现在不能期望这样
    似乎有一个bug导致了这种行为。您很可能正在经历它,因为您正在直接映射到另一个操作。通常,如果您有一个异步操作或类似的操作,减速机在侦听下一个操作的效果开始之前有时间完成

    也许这不是你问题的一部分,但是解决你指定问题的一个方法是在你的有效载荷的帮助下直接成功地导航到你的新路线,或者将有效载荷传递给ADVANCE

    以下链接是与您的项目相关的effects、store和rxjs项目中报告的问题:

    • /ReactiveX/rxjs/issues/2155(声誉太低,无法与此链接)

    看起来他们正在研究:)

    您使用的是什么版本?通过类似的安排,我看到减速器在效果之前处理动作。@cartant-我在问题中添加了版本。谢谢您的检查。我的
    @ngrx
    版本是相同的。你的RxJS版本怎么样?我的是5.2.0。您可能还希望在问题中包括您的
    NgModule
    引导。存储(通过reducer manager)和可观察到的效果动作都订阅了dispatcher。听起来你的特效好像在商店前订阅了调度器。@cartant-我有rxjs 5.1.1。我昨天花了好几个小时调试这个,结果一无所获。我今天还要多花点时间。谢谢你,吉莉。我不确定是否在有效期内调用
    this.store$.dispatch
    。我看不出它有什么根本性的错误,但我认为它应该是不必要的,因为效果能够将一个动作映射到另一个动作。现在,你确定ngrx特效会在操作到达减缩器之前拦截它们吗?这是关于中间件的redux官方文档-。这是我转述的一句话,“它提供了一个第三方扩展点,从发送一个动作到它到达减速机的那一刻。”我在我的项目中也使用了redux和effects,我根据自己的理解和经验回答。我之所以不将两个动作映射为一个动作,是因为我希望完全控制它们将被处理的顺序。没有必要这样做