关于正确使用 "side effect" 概念 ngrx/effects 的设计询问
Design interrogation on proper use of the "side effect" notion of ngrx/effects
我写这篇文章是为了知道我是否理解正确。
在网上找到的例子中,模式通常是这样的(这里的例子是 add/delete 对状态和远程数据库的操作):
effects.ts :
@Effect()
add$ = this.action$
.ofType(ADD)
.switchMap((action: Action) => {
return this.http.put(...)
.map( response => response.json() )
.map( response => Observable.of({ type: ADD_SUCCESS, payload: action.payload }))
.catch( response => Observable.of({ type: ADD_FAIL, payload: response.status }))
reducer.ts
...
switch (action.type){
case 'ADD_SUCCESS':
...
return new_state;
case 'ADD_FAIL':
return state;
}
有效,但用户感受到的执行速度取决于网络的速度。所以我想出了一个模式,它赌 return 从 API:
中没有错误的可能性很高
reducer.ts
...
switch (action.type){
case 'ADD':
... // make the adequate addition
return new_state;
case 'ADD_FAIL':
... // delete the addition previously made
return new_state;
}
effects.ts :
@Effect()
add$ = this.action$
.ofType(ADD)
.switchMap((action: Action) => {
return this.http.put(...)
.map( response => response.json() )
.catch( response => Observable.of({ type: ADD_FAIL, payload: action.payload }))
在这个模式中,保存到数据库的动作实际上是一个"side effect"。在 API return 错误的不太可能但可能的情况下,将采取第二个操作来撤消第一个操作。
但是我在网上给出的例子中还没有找到这种设计: 由于我是一个业余开发者,我想知道我是否遗漏了一些最终使它成为wrong/dangerous/inefficient的东西。
我不会说这有什么 wrong/dangerous/inefficient。一切都取决于您的程序要求。如果您正在处理 真正 慢速网络,则需要考虑到这一点。
但是在那种情况下,如果出现问题,那么在 Action 完成之前用户不会知道。在 真的 慢速网络并且同时具有 SUCCESS
和 FAIL
操作的情况下,用户对他们拥有的数据更有信心,因为 SUCCESS
动作必须开火。如果您绕过 SUCCESS
操作,那么用户可能正在工作并且在 FAIL
操作发生之前不知道他们的数据不正确。结果可能很小,也可能会中断用户的工作流程。
现在,一般来说,提交 put
或 post
请求并获得响应所需的时间应该相当短。并且您的 SUCCESS
或 FAIL
动作不应该太大以至于需要很长时间来计算。
以结账系统为例。用户去结帐并 posts
到服务器。在知道 post 是否成功之前,您不想路由到确认页面。因此,在这种情况下,必须有单独的 SUCCESS
和 FAIL
操作。
我认为它提供了最好的用户体验,以确保他们看到的数据是准确的,并且不会在失败后回滚更改。如果用户 posts
或 puts
向服务器发送某些内容,则 SUCCESS
操作应将其添加到应用程序状态,而不是在此之前以及可能的用户通知。 FAIL
操作将根据应用程序处理用户通知、潜在的日志记录等。
另一个例子:假设用户正在编辑在线个人资料。如果他们单击 'Save',那么您希望用户在服务器上成功保存时得到通知。这样他们就不会离开页面并想着“我希望它已保存,我没有得到回复。”
我会说在大多数情况下,同时执行 SUCCESS
和 FAIL
操作是合适的。但正如我所说,一切都取决于您的应用程序以及您的用户在您的环境中可以接受的内容。
希望对您有所帮助。
我写这篇文章是为了知道我是否理解正确。
在网上找到的例子中,模式通常是这样的(这里的例子是 add/delete 对状态和远程数据库的操作):
effects.ts :
@Effect()
add$ = this.action$
.ofType(ADD)
.switchMap((action: Action) => {
return this.http.put(...)
.map( response => response.json() )
.map( response => Observable.of({ type: ADD_SUCCESS, payload: action.payload }))
.catch( response => Observable.of({ type: ADD_FAIL, payload: response.status }))
reducer.ts
...
switch (action.type){
case 'ADD_SUCCESS':
...
return new_state;
case 'ADD_FAIL':
return state;
}
有效,但用户感受到的执行速度取决于网络的速度。所以我想出了一个模式,它赌 return 从 API:
中没有错误的可能性很高reducer.ts
...
switch (action.type){
case 'ADD':
... // make the adequate addition
return new_state;
case 'ADD_FAIL':
... // delete the addition previously made
return new_state;
}
effects.ts :
@Effect()
add$ = this.action$
.ofType(ADD)
.switchMap((action: Action) => {
return this.http.put(...)
.map( response => response.json() )
.catch( response => Observable.of({ type: ADD_FAIL, payload: action.payload }))
在这个模式中,保存到数据库的动作实际上是一个"side effect"。在 API return 错误的不太可能但可能的情况下,将采取第二个操作来撤消第一个操作。
但是我在网上给出的例子中还没有找到这种设计: 由于我是一个业余开发者,我想知道我是否遗漏了一些最终使它成为wrong/dangerous/inefficient的东西。
我不会说这有什么 wrong/dangerous/inefficient。一切都取决于您的程序要求。如果您正在处理 真正 慢速网络,则需要考虑到这一点。
但是在那种情况下,如果出现问题,那么在 Action 完成之前用户不会知道。在 真的 慢速网络并且同时具有 SUCCESS
和 FAIL
操作的情况下,用户对他们拥有的数据更有信心,因为 SUCCESS
动作必须开火。如果您绕过 SUCCESS
操作,那么用户可能正在工作并且在 FAIL
操作发生之前不知道他们的数据不正确。结果可能很小,也可能会中断用户的工作流程。
现在,一般来说,提交 put
或 post
请求并获得响应所需的时间应该相当短。并且您的 SUCCESS
或 FAIL
动作不应该太大以至于需要很长时间来计算。
以结账系统为例。用户去结帐并 posts
到服务器。在知道 post 是否成功之前,您不想路由到确认页面。因此,在这种情况下,必须有单独的 SUCCESS
和 FAIL
操作。
我认为它提供了最好的用户体验,以确保他们看到的数据是准确的,并且不会在失败后回滚更改。如果用户 posts
或 puts
向服务器发送某些内容,则 SUCCESS
操作应将其添加到应用程序状态,而不是在此之前以及可能的用户通知。 FAIL
操作将根据应用程序处理用户通知、潜在的日志记录等。
另一个例子:假设用户正在编辑在线个人资料。如果他们单击 'Save',那么您希望用户在服务器上成功保存时得到通知。这样他们就不会离开页面并想着“我希望它已保存,我没有得到回复。”
我会说在大多数情况下,同时执行 SUCCESS
和 FAIL
操作是合适的。但正如我所说,一切都取决于您的应用程序以及您的用户在您的环境中可以接受的内容。
希望对您有所帮助。