I'm not able to understand how dart async CancelableOperation.fromFuture works. It seems to cancel the first future but the .then is always executed.
While working with sockets I need to cancel a connection operation to avoid waiting for the socket timeout.
final op = f1
.then((_) => f2);
_connectOperation = CancelableOperation.fromFuture(op,
onCancel: () => throw CustomException());
return _connectOperation.valueOrCancellation();
f1 gets cancelled but f2 is still executed.
Anything that is happening inside op would not be affected in any way. Future does not have interface for cancellation intent to be communicated towards it.
The on-success-only action can be applied to _connectOperation.
_connectOperation = CancelableOperation.fromFuture(f1)
.then(
(value) => f2, // only runs if not cancelled
onCancel: () => throw CustomException()
);
Related
I am using flutter with redux and for handling stream data I'm using redux-epics.
Like this:
Stream<dynamic> getDataEpic(Stream<dynamic> actions, EpicStore<AppState> store) {
return Observable(actions)
.ofType(TypeToken<RequestDataAction>())
.flatMap((RequestDataAction action) {
return getDataStream()
.map(
(data) => UpdateStateWithData(data)
);
})
.takeUntil(actions.where((action) => action is CancelGetDataAction));
}
// getDataStream() - is a stream that returns some stuff...
In my screen in onInit I call store.dispatch(RequestDataAction()) and onDispose I call store.dispatch(CancelGetDataAction()) which destroys the Observable altogether, so the next time I go to this screen if I call store.dispatch(RequestDataAction()) my stream is not sending data, actually the entire Observable is dead!
How can I solve this problem? As far as I can see the problem is takeUntil because I completely closes the observable..
Try moving the takeUntil into the flatMap just after the getStreamData().map(). This will cancel the inner observable rather than the outer observable when the action is received.
I want to let RxJS Observable to handle my heavy job. But I want it make the subscription async if needed. For example:
const observable = Rx.Observable.create(function (observer) {
observer.next(1);
var cycle = 100;
while(cycle-- > 0){
observer.next(2);
}
observer.next(3);
observer.complete();
});
console.log('before');
observable.subscribe({
next: x => console.log('got value ' + x),
error: err => console.error('something wrong occurred: ' + err),
complete: () => console.log('done'),
});
console.log('after');
in this case, the after string gets printed after whole data out from observable. But I want observable to handle the heavy job and when needed, make the remaining of job async.
So one way that gets to my mind, is to put the heavy part in an setTimeout. I have searched the web but no solution achieved yet. What are the possible ways and which one is better?
Instead of using setTimeout, it's better to use the built-in RxJS scheduling mechanisms. For example, to make your subscription async, you can schedule it with the asyncScheduler, like this:
observable.pipe(
observeOn(asyncScheduler)
).subscribe(
...
)
Here is a demo: https://stackblitz.com/edit/rxjs-ahglez
I have a use case where I need to wait for a sequence of actions before I dispatch another using Redux Observables. I've seen some similar questions but I cannot fathom how I can use these approaches for my given use case.
In essence I want to do something like so:
action$
.ofType(PAGINATION_CLICKED) // This action occurred.
.ofType(FETCH_SUCCESS) // Then this action occurred after.
.map(() => analyticsAction()); // Dispatch analytics.
I would also like to cancel and start that sequence over again if another action of type FETCH_ERROR fires for example.
Great question. The important point is that action$ is a hot/multicast stream of all actions as they are dispatched (it's a Subject). Since it's hot we can combine it multiple times and they'll all be listening to the same stream of actions.
// uses switchMap so if another PAGINATION_CLICKED comes in
// before FETCH_SUCCESS we start over
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
action$.ofType(FETCH_SUCCESS)
.take(1) // <-------------------- very important!
.map(() => analyticsAction())
.takeUntil(action$.ofType(FETCH_ERROR))
);
So every time we receive PAGINATION_CLICKED we'll start listening to that inner Observable chain that listens for a single FETCH_SUCCESS. It's important to have that .take(1) because otherwise we'd continue to listen for more than one FETCH_SUCCESS which might cause strange bugs and even if not is just generally best practice to only take what you need.
We use takeUntil to cancel waiting for FETCH_SUCCESS if we receive FETCH_ERROR first.
As a bonus, if you decide you want also to do some analytics stuff based on the error too, not only start over, you can use race to indeed race between the two streams. First one to emit, wins; the other is unsubscribed.
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
Observable.race(
action$.ofType(FETCH_SUCCESS)
.take(1)
.map(() => analyticsAction()),
action$.ofType(FETCH_ERROR)
.take(1)
.map(() => someOtherAnalyticsAction())
)
);
Here's the same thing, but using race as an instance operator instead of the static one. This is a stylistic preference you can choose. They both do the same thing. Use whichever one is more clear to you.
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
action$.ofType(FETCH_SUCCESS)
.map(() => analyticsAction())
.race(
action$.ofType(FETCH_ERROR)
.map(() => someOtherAnalyticsAction())
)
.take(1)
);
I am trying to pass a value in the callback of an async meteor method. "mongoCollections" is global variable
// Async method
let waiter = function(cb) {
setTimeout(() => {
cb(undefined, {data: 'test', other: mongoCollections})
}, 1000);
}
// Meteor method
Meteor.methods({
'getCollections': () => {
let func = Meteor.wrapAsync(waiter);
let res = func();
return res;
}
});
On the client
Meteor.call('getCollections', (err, res) => {
console.log(err, res)
});
The issue is that in its current state the client callback is not fired, no error or anything.
But if I remove the "other: mongoCollections" part of the object then the callback is fired. Why would sending mongoCollections prevent the callback from being fired at all? If there is an error how can I catch it?
My guess is that you are loosing your context between waiter() and the execution of cb(), which means that mongoCollections is undefined in cb(), thus the call fails.
Try to log mongoCollections in the anonymous function that you setTimeout for. It will probably show as undefined.
Or try it like this:
let waiter = function(cb) {
var _mongoCollections = mongoCollections;
setTimeout(() => {
cb(undefined, {data: 'test', other: _mongoCollections})
}, 1000);
}
(which puts mongoCollections in the closure instsead)
Another possibility (based on comment below): Your mongoCollections object is not serializable. You can try it by logging the result of JSON.stringify(mongoCollections). If this fails you have to extract the parts of the object you need, that can be serialized.
There are a number of things that could be happening here, but my guess is that an error is occurring somewhere and the error message is getting swallowed by a handler somewhere deeper.
You probably want to be using Meteor.setTimeout instead of vanilla setTimeout at a minimum. Have a look here: http://docs.meteor.com/api/timers.html#Meteor-setTimeout
Beyond that, I would follow the previous answerer's advice and try to make sure that mongoCollections is as global as you think it is. If the only change between the callback working and not working is the addition of a single symbol, then the culprit is likely that your added symbol is undefined.
I have this question in my head, not sure if this is validate or not, below it's an example of redux middle console log out the store.
const logger = store => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
I can see it's using currying, so in redux is calling as logger(store)(store.dispatch)(action) (Correct me if i am wrong). My question is why we currying here instead just
(store, next, action) => { // do the rest }
Thanks for any suggestion I am slowly moving into functional programming too to get my head up rhythm with it.
I think redux wants to provide three hooks to developers.
We can split the call chain logger(store)(next)(action) into
let haveStoreAndDispatch = logger(store);
let haveNext = haveStoreAndDispatch(next);
let haveAction = haveNext(action);
Then we get three hook functions.
In haveStoreAndDispatch callback function, store have been created.
In haveNext callback function, we have get the next middleware.
In HaveAction callback function, we can do something with the previous middleware's result action.
Callbacks haveStoreAndDispatch and haveNext just be called only once in applyMiddleware(...middlewares)(createStore).