I have a function that will do some stuff asynchronously, but doesn't expose an async and instead will call a callback with the result when finished. I want to turn that into an async, and have come up with this code, but doesn't seem quite right. Any better way to do it?
async {
let ev = Event<_>()
someAsyncExternalCodeThatWillCallTheCallbackWhenDone(fun value -> ev.Trigger value)
let! value = Async.AwaitEvent(ev.Publish)
return value
}
Any advantage of using an Observable or a ManualResetEvent instead of an Event in this scenario?
I think the idiomatic solution in this case is to use Async.FromContinuations:
Async.FromContinuations(fun (cont, econt, ccont) ->
someAsyncExternalCodeThatWillCallTheCallbackWhenDone(cont))
The FromContinuations function also lets you handle exceptions (call econt if an exception occurs) or cancellation (and you can see it as the basic way to create async computations).
That said, I don't think there is anything wrong with using events. The code with events implements pretty much the same logic (I think) but in a more complex way.
Related
I have two observables
baseObs$ = serviceCall(); // this return Observable<Foo>
secondObs$ = serviceCall(args); // this return Observable<Bar>
args in this example is public variable defined somewhere else. It doesn't need to be though if that makes this easier.
baseObs I can call whenever I want, but secondObs I can only call after baseObs is succesfully called and handled (don't know the right words so example follows):
I have now something like
baseObs$.subscribe(x => {
const args = x.args; // just example. Point is, I need x to build args.
serviceCall(args).subscribe(y => {
console.log(y); // This is fine
});
});
This suits my needs but I got feedback that no subscribe should live inside another subscribe. How would you achieve same thing using baseObs$ and secondObs$ defined above?
PS. All is pseudo code but hopefully I didn't do too much typos. I think the idea should be clear though.
In the simple case that the first observable only emits once (like a typical HTTP request), any one of switchMap, mergeMap etc. will do:
serviceCall().pipe(
switchMap(x => serviceCall(x.args))
).subscribe(console.log);
If that assumption is not true, you're going to want to read their respective documentation to understand how behavior will change between them. In fact, I'd recommend reading up on them to know their differences even just in general, as it's very valuable information when dealing with reactive code.
Is it ok to write:
getFieldX().clear().sendKeys('abc');
or should I write:
getFieldX().clear().then( () => sendKeys('abc));
I'm totally confused about the Promise handling in protractor. clear() returns a promise, so I should use .then() afterwards, shouldn't I?
But I found examples with .then and some without.
Protractor itself has an example without .then():
https://www.protractortest.org/#/control-flow
Does Protractor has its own mechanism and resolves one after the other promise so there is no need for using .then() after a protractor call that returns a Promise?
And is the control flow of protractor only active in a spec?
When using .sendKeys() in a normal function I have to use .sendKeys().then(...) ?
This all depends on if you are using SELENIUM_PROMISE_MANAGER or not. As this is (has?) becoming deprecated, I would not use it. It should be set to false by default, but if you want to be sure you can add SELENIUM_PROMISE_MANAGER = false; to your conf file. The way that protractor has been moving is to use async/await, so your sendKeys function would look like:
let field = element(by.css('CSS.Selector'));
await field.clear();
await field.sendKeys('abc');
Because these are async functions, you will need to define your function properly, so a basic spec would look like:
describe('Demonstrating async/await',function(){
it('Should send some keys', async function(){
let field = element(by.css('CSS.Selector'));
await field.clear();
await field.sendKeys('abc');
});
});
The important difference there is that a function needs to be defined as async function(). As far as reading the code goes, await simply can be read as "Wait until promise resolved to move on". It does get a bit tedious and you feel like you write await before every line of code (you basically do), but I find it significantly better than .then() trees.
This question already has answers here:
Am I right to ignore the compiler warning for lacking await for this async call?
(3 answers)
Closed 7 years ago.
Below is my code. Compiler gives warning because AddLog is not awaited. I do not want to await this call and want to continue executing next lines. I dont have any concern if the exception is consumed also. Is it fine to ignore the warning?
public async Task Add()
{
this.AddLog( "Add executing" );
// Logic to Add Customer
}
public async Task AddLog( string message )
{
// Write to DB
}
Assuming you truly want to call the AddLog method in a fire-and-forget way, then you have a few options.
If, by design, you want AddLog to always be invoked as a fire-and-forget method, then you could change the signature to not return a Task.
public async void AddLog( string message ) // change Task to void
{
// Write to DB
// WARNING: Make sure that exceptions are handled in here.
}
However, if you do this, you better make sure that exceptions are properly handled from within the AddLog method. If any exception goes unhandled, it will crash your process.
Another option is to change the way you invoke AddLog to clearly state your intent that you don't care about when the Task completes, or about any exceptions that may be raised. You can do this by defining an empty continuation (Well, almost empty. See my edit at the bottom of the post for why it's a good idea to read the Task.Exception property at the very least).
// see EDIT for why the Task.Exception property is read here.
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
With either option, unless you are awaiting on other code inside your Add method that you are not showing us, then there is no longer any point in defining your Add method as async. You can simply turn it into a regular synchronous method. Otherwise, you'll then get another warning telling you that This async method lacks 'await' operators and will run synchronously....
public void Add() // no need for "async Task"
{
// see EDIT for why the Task.Exception property is read here.
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
// Logic to Add Customer
}
In any case, I wouldn't simply ignore the warning. Much like sometimes we get the warning Use of unassigned local variable 'x' in cases where we know that our code is fine, we typically don't ignore the warning. Instead, we may explicitly initialize the variable to null just to make our intent clear, and make the warning go away. Similarly, you can make the warning go away by making your intentions more explicit to the compiler using one of the above options.
EDIT: Word of caution about unobserved exceptions
I should also mention that even with the ContinueWith option, you may have to be careful about unhandled exceptions that come from your AddLog method.
According to this article, the way unobserved exceptions from tasks are handled has changed between .NET 4.0 and .NET 4.5. So, if you are still running .NET 4.0, or if you forcing .NET 4.0 exception behavior via configuration, you run the risk that unhandled exceptions will crash your process whenever the task gets GC-collected and finalized.
To make sure that this is not a problem, you can adjust the continuation to explicitly observe the exception, if any is present. You don't actually need to do anything with it, you just need to read it. This is one way to do it safely:
this.AddLog("Add executing").ContinueWith(t => { var observed = t.Exception; });
I've updated my earlier examples above to use the safer version of the continuation.
I would make add() non async since it isn't...and then task.run on add log
Good day!
I began writing my own basic JavaScript library for personal use and distribution a few days ago, but I am having trouble with one of the methods, specifically bind().
Within the method itself, this refers to the library, the object.
I went to Google and found function.call(), but it didn't work out the way I planned it--it just executed the function.
If you take a look at another method, each(), you'll see that it uses call() to pass values.
I also tried the following:
f.arguments[0]=this;
My console throws an error, saying it cannot read '0' of "undefined".
I would like to be able to pass this (referencing the library--NOT THE WINDOW) to use it in the event listener.
You can see it starting at line 195 of the JavaScript of this JSFiddle.
Here it is as well:
bind:function(e,f){
if(e.indexOf("on")==0){
e=e.replace("on","");
}
if(typeof f==='function'){
/*Right now, 'this' refers to the library
How can I pass the library to the upcoming eventListener?
*/
//f=f(this); doesn't work
//f.call(this); //doesn't work
//this.target refers to the HTMLElement Object itself, which we are adding the eventListener to
//the outcome I'm looking for is something like this:
/*$('h3').which(0).bind(function({
this.css("color:red");
});*/
//(which() defines which H3 element we're dealing with
//bind is to add an event listener
this.target.addEventListener(e,f,false)
}
return this;
},
Thank you so much for your help, contributors!
If, as per your comments, you don't want to use .bind(), rather than directly passing f to addEventListener() you could pass another function that in turn calls f with .call() or .apply():
if(typeof f==='function'){
var _this = this;
this.target.addEventListener(e,function(event){
f.call(_this, event);
},false)
}
Doing it this way also lets your library do any extra event admin, e.g., pre-processing on the event object to normalise properties that are different for different browsers.
So in this particular case you actually want to call JavaScript's built in bind method that all functions have.
f = f.bind(this);
f will be a new function with it's this argument set to whatever you passed into it.
Replace f=f(this); with f.apply(this);
Look at underscore code, here:
https://github.com/jashkenas/underscore/blob/master/underscore.js#L596
I'm using Tornado web server and want to take advantage of static caching for an asynchronous query result. Python makes it easy to wrap a function with a cache of some sort, for example using a decorator:
#cache.wrap(ttl=60)
def get_data(arg):
return do_query(arg)
However, it quickly gets complex using continuation passing:
def wrap_static_result(key, result, callback, ttl):
cache.set(key, result, ttl)
callback(result)
def get_data(arg, callback):
cached = cache.get(arg)
if cached:
callback(cached)
else:
callback2 = lambda result: wrap_static_result(arg, result, callback, ttl=60)
do_async_query(arg, callback2)
The most elegant solution I can think of requires making assumptions about call signatures, which isn't always practical. Can anyone think of a nicer way?
Use Deferreds. (The lack of such an abstraction is one of the reasons that Tornado is dramatically inferior to Twisted. You may want to check out Cyclone while you're at it.)