I am currently creating a Backbone.js and jquery Mobile web application and I have some calls to Backbone.model.fetch().
I have the proper success and error-callbacks, but there is some code that I want to execute no matter if the fetch was successfull or not.
Currently, I'm simply copying the common code. But I asked myself if there is any callback that is executed no matter what happens.
Like the try{} catch{} finally{} from C#.
Is there anything like that?
fetch() returns a 'Deferred Object'
see: http://api.jquery.com/category/deferred-object/
it's not really like try{} catch{}, but you can use .always() method to bind a callback which will be executed after the request is done (no matter if it was successful or not)
like so.
var doSomething = function () {
//will run after fetch() request is finished
};
collection.fetch().always(doSomething);
similarly, instead of passing success or error callbacks to fetch()'s options, in general it is encouraged to chain .done(), .fail(), or .then() methods to deferred methods(fetch, save...etc)
Related
I'm converting dart code to nnbd.
I have the following code.
var subscription = response.listen(
(newBytes) async {
/// if we don't pause we get overlapping calls from listen
/// which causes the [writeFrom] to fail as you can't
/// do overlapping io.
subscription.pause();
/// we have new data to save.
await raf.writeFrom(newBytes);
subscription.resume();
});
The problem is I get the following error:
The non-nullable local variable 'subscription' must be assigned before it can be used.
Try giving it an initializer expression, or ensure that it's assigned on every execution path.
I've had a similar problem solved here:
dart - correct coding pattern for subscription when using null saftey?
which was answered by #lrn
However the pattern solution pattern doesn't seem to work in this case.
raf.writeFrom is an async operation so I must use an 'async' method which means I can't use the 'forEach' solution as again I don't have access to the subscription object.
If you really want to use listen, I'd do it as:
var subscription = response.listen(null);
subscription.onData((newBytes) async {
subscription.pause();
await raf.writeFrom(newBytes);
subscription.resume();
});
or, without the async:
var subscription = response.listen(null);
subscription.onData((newBytes) {
subscription.pause(raf.writeFrom(newBytes));
});
which will pause the subscription until the future returned by raf.writeFrom completes (it shouldn't complete with an error, though).
If using listen is not a priority, I'd prefer to use an asynchronous for-in like:
await for (var newBytes in subscription) {
await raf.writeFrom(newBytes);
}
which automatically pauses the implicit subscription at the await and resumes it when you get back to the loop.
Both with stream.listen and the StreamController constructor, null safety has made it nicer to create them first without callbacks, and then add the callbacks later, if the callback needs to refer to the subscription/controller.
(That's basically the same nswer as in the linked question, only applied to onData instead of onDone. You have to pass a default onData argument to listen, but it can be null precisely to support this approach.)
I don't think your code, as written, was legal before null-safety either; you can't reference a variable (subscription) before it's declared, and the declaration isn't complete until after the expression you initialize it with (response.listen(...)) is evaluated. You will need to separate the declaration from the initialization to break the circular dependency:
StreamSubscription<List<int>> subscription;
subscription = response.listen(...);
I am trying to migrate from RxJava1 to RxJava2. I am replacing all code parts where I previously had Observable<Void> to Compleatable. However I ran into one problem with order of stream calls. When I previously was dealing with Observables and using maps and flatMaps the code worked 'as expected'. However the andthen() operator seems to work a little bit differently. Here is a sample code to simplify the problem itself.
public Single<String> getString() {
Log.d("Starting flow..")
return getCompletable().andThen(getSingle());
}
public Completable getCompletable() {
Log.d("calling getCompletable");
return Completable.create(e -> {
Log.d("doing actuall completable work");
e.onComplete();
}
);
}
public Single<String> getSingle() {
Log.d("calling getSingle");
if(conditionBasedOnActualCompletableWork) {
return getSingleA();
}else{
return getSingleB();
}
}
What I see in the logs in the end is :
1-> Log.d("Starting flow..")
2-> Log.d("calling getCompletable");
3-> Log.d("calling getSingle");
4-> Log.d("doing actuall completable work");
And as you can probably figure out I would expect line 4 to be called before line 3 (afterwards the name of andthen() operator suggest that the code would be called 'after' Completable finishes it's job). Previously I was creating the Observable<Void> using the Async.toAsync() operator and the method which is now called getSingle was in flatMap stream - it worked like I expected it to, so Log 4 would appear before 3. Now I tried changing the way the Compleatable is created - like using fromAction or fromCallable but it behaves the same. I also couldn't find any other operator to replace andthen(). To underline - the method must be a Completable since it doesn't have any thing meaning full to return - it changes the app preferences and other settings (and is used like that globally mostly working 'as expected') and those changes are needed later in the stream. I also tried to wrap getSingle() method to somehow create a Single and move the if statement inside the create block but I don't know how to use getSingleA/B() methods inside there. And I need to use them as they have their complexity of their own and it doesn't make sense to duplicate the code. Any one have any idea how to modify this in RxJava2 so it behaves the same? There are multiple places where I rely on a Compleatable job to finish before moving forward with the stream (like refreshing session token, updating db, preferences etc. - no problem in RxJava1 using flatMap).
You can use defer:
getCompletable().andThen(Single.defer(() -> getSingle()))
That way, you don't execute the contents of getSingle() immediately but only when the Completablecompletes and andThen switches to the Single.
I have a very established n-tiered ASP.NET MVC application that currently does everything synchronously; all controllers inherit from Controller rather than AsyncController.
What I want to do is to take one of the lower tiers (that literally every flow consumes) and put in an awaited call to a WCF. Why await? Well, I figure that it will reduce the overall thread-count and make the server more scalable.
However, I am not in a position to change any of the code outside of this tier. So normally, one would change the calling methods from returning T to return 'async Task', and give the method name an "async" suffix, e.g.:
from
public string GetData()
to
public Task<string> GetDataAsync()
Okay, so I went about it with the following (cut down) code:
public ResponseObject GetSomething(RequestObject request)
{
return MyMethodAsync(request).Result;
}
private static async Task<ResponseObject> MyMethodAsync(RequestObject request)
{
using (var client = new Client(new NetTcpBinding(), new EndpointAddress(Url))))
{
await client.DoSomething(request).ConfigureAwait(true);
}
}
When I run this code (F5), it gets to the line where it calls the "await client.DoSomething(request).ConfigureAwait(true);" and then, unfortunately, that's the last I see of my thread. Occassionally it does return when I'm debugging (F11), but 99% of the time it doesn't.
The non-ASYNC method works perfectly fine
Debugging the WCF service shows it receives the request, processes it and returns
Using a console app, this works perfectly. It's only when I try this in one of my "middle" tiers of my web application that the thread disappears.
I've tried with .ConfigureAwait(true) and .ConfigureAwait(false).
Short answer: don't block on async code (your problem's the .Result which blocks, while its Task is a concurrent one, not a parallel one)
Long answer (and really good reading, too): Don't Block on Async Code
I'm using the HotTowel SPA template which makes use of Durandal. In my Durandal ViewModels I am using Breeze to get some data from the database.
I have a datacontext class that I put all my breeze queries in and the queries all follow the pattern like the following:
getAthletes: function (queryCompleted) {
var query = breeze.EntityQuery.from("Athletes");
return manager
.executeQuery(query)
.then(queryCompleted)
.fail(queryFailed)
}
Since I'm doing an asynchronous call in the activate method of the view model, I have to return the promise that comes back from these calls in the activate method.
Using a single query works great like this:
function activate() {
datacontext.getAthlete(loadAthlete);
}
However, if I need to perform two queries I run into problems, but only in the release version of my application. I have tried doing this with the following syntax:
function activate() {
datacontext.getAthlete(loadAthlete).then(datacontext.getOtherData(loadOtherData));
}
This will work fine in debug mode, but when I deploy it out to the server and my scripts get bundled, I get an exception which isn't very clear.
t is not a function
I've also tried chaining them together in my datacontext class like below, but I still get the same error.
getAthleteAndEfforts: function (athleteId, athleteQueryCompleted, effortsQueryCompleted) {
var athleteQuery = breeze.EntityQuery.from("Athletes").where("id", "==", athleteId);
var effortsQuery = breeze.EntityQuery.from("BestEfforts").where("athleteId", "==", athleteId);
return manager.executeQuery(athleteQuery).then(athleteQueryCompleted)
.then(manager.executeQuery(effortsQuery).then(effortsQueryCompleted))
.fail(queryFailed);
}
So I'm assuming I just don't understand the Q.defer() enough to use it properly or there is something else going on.
What is the correct syntax to accomplish this?
Ok, thanks to RainerAtSpirit for pointing me in the right direction to find this. I looked at John Papa's jumpstarter examples and he has a datacontext that does this under the primeData function.
So using the syntax he used there I was able to get it to work correctly like this:
getAthleteAndEfforts: function (athleteId, athleteQueryCompleted, effortsQueryCompleted) {
return Q.all([
datacontext.getAthlete(athleteId, athleteQueryCompleted),
datacontext.getAthleteEfforts(athleteId, effortsQueryCompleted)]);
}
I had seen the Q.all in the Q documentation but wasn't sure how to use it, but this example helped. I tested this and it works both in debug and release modes.
Not sure why the first version is working at all, but you'd return a promise when datacontext is making async calls.
function activate() {
return datacontext.getAthlete(loadAthlete);
}
or
function activate() {
return datacontext.getAthlete(loadAthlete).then( return datacontext.getOtherData(loadOtherData));
}
Check #John Papa's jumpstarter for more examples: https://github.com/johnpapa/PluralsightSpaJumpStartFinal/search?q=activate
I work on a project with durandal/breeze. I have the following code in my activate function:
var activate = function (routeData) {
initLookups();
var idTran = parseInt(routeData.idTran);
var idItin = parseInt(routeData.idItin);
if (idItin == -1)
idItin = datacontext.createItineraryDetailTransport(idTran);
datacontext.getTransportById(idTran, transport);
datacontext.getItineraryById(idItin, itinerary);
}
As you can see in the above code, I have 3 calls to the datacontext:
datacontext.createItineraryDetailTransport >> eventually... if (idItin == -1)
datacontext.getTransportById
datacontext.getItineraryById
The problem right now is that each call is not waiting for the previous one to complete before executing.
My question: how to proceed to be sure one call is finished before executing the next one? Please note that the first call is inside a condition... I'm thinking of using 'promises' but don't know.
Thanks.
The tricky part to what you're trying to do is conditionally chain three calls together.
You can simply chain multiple calls together using the then() method. However in your case, you need an initial promise to chain when the first condition isn't met.
The $.when() method is the trick here, because you can either chain an promise returned by Breeze, or you can chain a "dummy" promise, which is what $.when() gives you. If the first parameter passed to $.when is not a promise, then it returns a promise that is immediately resolved.
If I understand your question correctly, you should be able to write your code something like this:
var activate = function (routeData) {
initLookups();
var idTran = parseInt(routeData.idTran);
var idItin = parseInt(routeData.idItin);
var idtDeferred = $.when();
if (idItin == -1)
idtDeferred = datacontext.createItineraryDetailTransport(idTran);
idtDeferred
.then(datacontext.getTransportById(idTran, transport))
.then(datacontext.getItineraryById(idItin, itinerary));
}
Your code example looks like datacontext.createItineraryDetailTransport is supposed to set the idItin var, but I'm assuming that it returns a promise like typical breeze queries.
Certain parts of your example are unclear to me.
Is initLookups asynchronous? If so, do you have to wait for it to complete before performing the other asynchronous steps?
How can createItineraryDetailTransport be asynchronous when it returns the integer, idItin?
What the heck does createItineraryDetailTransport actually do? My guess is that idItin == -1 when you don't have an ItineraryDetailTransport entity yet and therefore don't have the key you need to call getItineraryById. If so, you have to restructure the signature of createItineraryDetailTransport.
Why does getItineraryById have to wait for getTransportById when they seemingly have nothing in common?
What are transport and itinerary? I'm guessing they are accidentally omitted variables that will be set with the results of the async calls within those datacontext methods.
Where is your error handling? What should happen if one of the async calls fails?
These issues must be sorted out before someone can give you a really good answer.
Joseph Gabriel seems to me to be mostly on the right track although I might have written it a little differently
...
var transport, itinerary;
var promise = (idItin == -1) ?
datacontext.createItineraryDetailTransport(aCallBackThatSets_idItin) :
Q.resolve(); // creates a resolved promise
promise = promise
.then(datacontext.getTransportById(idTran, transport)
.then(datacontext.getItineraryById(idItin, itinerary))
.fail(yourErrorHandler);
return promise; // don't forget to return the promise!
The most important step missing from Joseph Gabriel's suggestion ... and the reason you couldn't make his suggestion work ... is that it neglected to return the promise.
You must return a promise if you want Durandal to wait before activating the view.