We are in the process of adopting the Nx framework from Nrwl.io for our Angular applications.
As part of this we are trying to understand the underlying implementation differences between the optimisticUpdate and pessimisticUpdate methods in the data persistence module.
According to the documentation, pessimisticUpdate will update the server before the client whilst with optimisticUpdate, the client is updated first.
However the source code on github for both methods is as follows
export function pessimisticUpdate<T, A extends Action>(
opts: PessimisticUpdateOpts<T, A>
) {
return (source: ActionStateStream<T, A>): Observable<Action> => {
return source.pipe(
mapActionAndState(),
concatMap(runWithErrorHandling(opts.run, opts.onError))
);
};
}
export function optimisticUpdate<T, A extends Action>(
opts: OptimisticUpdateOpts<T, A>
) {
return (source: ActionStateStream<T, A>): Observable<Action> => {
return source.pipe(
mapActionAndState(),
concatMap(runWithErrorHandling(opts.run, opts.undoAction))
);
};
}
On the face of it, separating updates into optimistic and pessimistic seems to be very useful but essentially the implementation of both methods seems to be identical and we are struggling to understand what the is for having both methods.
Additionally the example code for calling the optimisticUpdate method does not dispatch an action when the run method has completed successfully. My understanding is that this would end the stream - there is no indication of what the backend call should be returning.
class TodoEffects {
@Effect() updateTodo = this.s.optimisticUpdate('UPDATE_TODO', {
// provides an action and the current state of the store
run: (a: UpdateTodo, state: TodosState) => {
return this.backend(state.user, a.payload);
},
undoAction: (a: UpdateTodo, e: any) => {
// dispatch an undo action to undo the changes in the client state
return ({
type: 'UNDO_UPDATE_TODO',
payload: a
});
}
});
Can anyone who has been using Nx shed any light on what the difference is and also what we need to do implement in our service for an optimistic update.
Nx comes with two versions of these: an RxJs pipeable operator
version and a member of the DataPersistence class.
The former needs an Observable to pipe, which you need to provide (these are the functions you found in the first code block). The latter looks like your second code block.
The difference between optimistic and pessimistic as implemented is only that there is the ability to roll back an optimistic update (provided with the undoAction
). This is because in an optimistic call we update the UI right away and send a network call to update the server. If the server call is unsuccessful we need to roll back that UI change that we made. This won't apply in a pessimistic call because we'd have a loading spinner or other mechanism to avoid updating the UI while the call is in flight.
For your second code block, the run
function is not returning an action. This should be updated in the Nx docs.
class TodoEffects {
@Effect() updateTodo = this.s.optimisticUpdate('UPDATE_TODO', {
run: (a: UpdateTodo, state: TodosState) => {
return this.backend(state.user, a.payload)
.pipe(
map(resp => ({
type: 'UPDATE_TODO_SUCCESS',
payload: resp
}))
);
}