RxJS retry() semantics - javascript

Given this example for .retry():
// Try three times to get the data and then give up
var source = get('url').retry(3);
What does get() return? Can someone provide an implementation to make the example work? i.e. to actually retry some asynchronous code 3 times.
I'm just starting out with RxJS, and am trying to understand the semantics, and getting an example of the above would really help, thanks!

get returns an Observable. What retry does is it subscribes to the underlying Observable and captures an onError call and then resubscribes to the Observable while hiding the onError from downstream thus keeping the stream from terminating. Only requirement for the Observable is that it must "start on subscribe" semantics or in other words is a cold Observable.
So get could be implemented as:
function get() {
var count = 0;
return Rx.Observable.create(function(observer) {
if (++count < 2) observer.onError(new Error());
else {
observer.onNext("Yay!");
observer.onCompleted();
}
});
}
Edit
I re-read your question and think I misunderstood what you were asking. The first example I gave is just a quick way of seeing how to make a trivial Observable that will work with retry. In the scenario that is given of get it is doing some sort of http request.
The following is using the RxJS-DOM Library to do the Ajax request but you could use other libraries that have Promises as well.
//With RxJS DOM
function get(url) {
return Rx.DOM.ajax({url : url});
}
//With JQuery Promises
function get(url) {
return Rx.Observable.defer(function() {
return $.ajax(url);
});
}
In both cases you are hitting some remote server resource which could potentially error. Adding a retry after it would make sure that the issue is not a transient network issue.

Related

Observable determine if subscriber function has finished

What is the best way to determine if the subscriber has finished executing or better yet return something and catch it up-stream? For example:
this._subscriptions.push(this._client
.getCommandStream(this._command) // Returns an IObservable from a Subject stream
.subscribe(msg => {
// Do some processing maybe some promise stuff
http.request(url).then(
// some more stuff
);
});
What's the best know to determine that subscription has finished. I've implemented it as follows:
this._subscriptions.push(this._client
.getCommandStream(this._command)
.subscribe(msg => {
// Do some processing maybe some promise stuff
http.request(url).then(re => {
// some more stuff
msg.done()
}).catch(err => msg.done(err));
});
i.e. added a done method to the object being passed in to determine if this is finished. The issue with that is I'll have to call done in every promise or catch block and find that a little too exhaustive. Is there a cleaner and more automated way of doing this?
I think the examples I've given are not good enough. This implementation is using RX to build an internal messaging bus. The get command stream is actually returning a read-only channel (as an Observable) to get commands and process them. Now the processing could be a http request followed by many other things or just an if statement.
this._client
.getCommandStream(this._command) // Returns an IObservable from a Subject stream
.subscribe(msg => {
// Do some processing maybe some promise stuff
http.request(url).then({
// some more stuff
}).then({
// Here I wanna do some file io
if(x) {
file.read('path', (content) => {
msg.reply(content);
msg.done();
});
} else {
// Or maybe not do a file io or maybe even do some image processing
msg.reply("pong");
msg.done()
}
});
});
I feel like this is a fine usage of the Observable pattern as this is exactly a sequence of commands coming in and this logic would like to act on them. The question is notice msg.done() being called all over the place. I want to know what is the best way to limit that call and know when the entire thing is done. Another option is to wrap it all in a Promise but then again what's the difference between resolve or msg.done()?
Actually, making another asynchronous request inside subscribe() isn't recommended because it just makes things more complicated and using Rx in this way doesn't help you make your code more understandable.
Since you need to make a request to a remote service that returns a PRomise you can merge it into the chain:
this._subscriptions.push(this._client
.getCommandStream(this._command)
.concatMap(msg => http.request(url))
.subscribe(...)
Also the 3rd parameter to subscribe is a callback that is called when the source Observable completes.
You can also add your own teardown logic when the chain is being disposed. This is called after the complete callback in subscribe(...) is called:
const subscription = this._subscriptions.push(this._client
...
.subscribe(...)
subscription.add(() => doWhatever())
Btw, this is equivalent to using the finally() operator.
As per RxJs subscribe method documentation, the last Argument is completed function
var source = Rx.Observable.range(0, 3)
var subscription = source.subscribe(
function (x) {
console.log('Next: %s', x);
},
function (err) {
console.log('Error: %s', err);
},
function () {
console.log('Completed');
});
please refer this documentation
https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/subscribe.md

Get return value from subcribe on Observable

Using RxJS 5.0.0-rc.1, I'm trying to communicate my Observer and Observable in a way similar to how generators/iterators work by exchanging data using yield and .next(). The intention is to get a hold of what a call to .subscribe returns and modify/update following values in my observable stream depending on that.
I'm not entirely sure if this is, at all, possible. Though, I found out that you can catch exceptions thrown on .subscribe callbacks. The following snippets prints out "Boom!":
var source = Observable.create((observer) => {
try {
observer.next(42);
} catch (e) {
// This will catch the Error
// thrown on the subscriber
console.log(e.message);
}
observer.complete();
});
source.subscribe(() => {
throw new Error('Boom!');
});
So, what if instead of throwing, the subscriber returns a value? Is there a way for the Observable to retrieve it? Perhaps I'm approaching this the wrong way. If so, what's the "reactive" way of doing things in this scenario?
Many thanks.
EDIT
One possible way I came up with is by providing a callback function on every item in the stream. Something like:
var source = Observable.create((observer) => {
// This will print "{ success: true }"
observer.next({ value: 42, reply: console.log });
observer.complete();
});
source.subscribe(({ value, reply }) => {
console.log('Got', value);
return reply({ success: true });
});
Any other thoughts?
EDIT 2
Since my original question brought some confusion on what I was trying to achieve, I'll describe my real world scenario. I'm writing the API of a module for managing messages through queues (much like a simplified, in memory, AMQP-RPC mechanism) and I though RxJS would be a good fit.
It works like you would expect: a Publisher pushes messages to a queue, which get delivered to a Consumer. In term, the Consumer can reply to the Publisher, which can listen to that response if it's interested.
In an ideal scenario, the API would look something like this:
Consumer().consume('some.pattern')
.subscribe(function(msg) {
// Do something with `msg`
console.log(msg.foo);
return { ok: true };
});
Publisher().publish('some.pattern', { foo: 42 })
// (optional) `.subscribe()` to get reply from Consumer
That example would print 42.
The logic for replying to the Publisher lies within the Consumer function. But the actual response comes from the .subscribe() callback. Which leads me to my original question: how should I go about fetching that returned value from the creator of the stream?
Think of Consumer#consume() as:
/**
* Returns an async handler that gets invoked every time
* a new message matching the pattern of this consumer
* arrives.
*/
function waitOnMessage(observer) {
return function(msg) {
observer.next(msg);
// Conceptually, I'd like the returned
// object from `.subscribe()` to be available
// in this scope, somehow.
// That would allow me to go like:
// `sendToQueue(pubQueue, response);`
}
}
return Observable.create((observer) => {
queue.consume(waitOnMessage(observer));
});
Does it make any more sense?
There are indeed similarities between generators and observables. As you can see here, observables (asynchronous sequence of values) are the asynchronous version of iterables (synchronous sequence of values).
Now, a generator is a function which returns an Iterable. However, Rxjs Observable encloses both a generator - a.k.a producer (that you execute/start by calling subscribe) and the produced asynchronous sequence of values (that you observe by passing an Observer object). And the subscribe call returns a Disposable which allows you to stop receiving values (disconnect). So while generators and observables are dual concepts, the APIs to use them differ.
You cannot do two-way communication by default with the rxjs observable API. You probably could manage to do it by constructing yourself the back channel through subjects (note that you MUST have an initial value to kick off the cycle).
var backChannel = Rx.Subject();
backChannel.startWith(initialValue).concatMap(generateValue)
.subscribe(function observer(value){
// Do whatever
// pass a value through the backChannel
backChannel.next(someValue)
})
// generateValue is a function which takes a value from the back channel
// and returns a promise with the next value to be consumed by the observer.
You could consider wrapping that with :
function twoWayObsFactory (yield, initialValue) {
var backChannel = Rx.BehaviorSubject(initialValue);
var next = backChannel.next.bind(backChannel);
return {
subscribe : function (observer) {
var disposable = backChannel.concatMap(yield)
.subscribe(function(x) {
observer(next, x);
});
return {
dispose : function (){disposable.dispose(); backChannel.dispose();}
}
}
}
}
// Note that the observer is now taking an additional parameter in its signature
// for instance
// observer = function (next, yieldedValue) {
// doSomething(yieldedValue);
// next(anotherValue);
// }
// Note also that `next` is synchronous, as such you should avoir sequences
// of back-and-forth communication that is too long. If your `yield` function
// would be synchronous, you might run into stack overflow errors.
// All the same, the `next` function call should be the last line, so order of
// execution in your program is the same independently of the synchronicity of
// the `yield` function
Otherwise, the behaviour you describe seems to be that of an asynchronous generator. I never used such, but as this is a proposal for some future version of javascript, I think you can
already start trying it out with Babel (cf. https://github.com/tc39/proposal-async-iteration).
EDIT :
If you are looking for a loop-back mechanism (less general purpose approach but could very well fits your use case, if what you want to do is simple enough), the expand operator could help. To understand its behaviour, please check the doc, and the following answers on SO for examples of use in concrete contexts:
RxJS: Backpressure with switchMap producing N values
Circular Dependencies with RxJS. Modeling spores
How to build an rx poller that waits some interval AFTER the previous ajax promise resolves?
Basically expand allows you to both emit a value downstream and feed that value back at the same time in your producer.

How to wrap jsonP callback in native javascript Promise?

I'm playin with native Promise to combine a bunch of XmlHttpRequests into one result and I think I got it working, see http://jsfiddle.net/pjs06hdo/
(random calls to flickr api, see the console for what's actually going on in which order)
There might be shorter implementations but with this code I can understand what's going on.
But then there comes the stupid JSONP :-( as it turns out the actual target site does not allow Cross-site requests and I have to use a provided jsonP endpoint (again simulated with flickr) And here I'm stuck: that stupid global callback does not fit into my basic understanding of Promise
I think the solution has to do with explanations in How do I convert an existing callback API to promises?.
I tried to implement this but it works only partially: http://jsfiddle.net/b33bj9k1/ There is no actual output, only console messages, sorry. But there you can see that there are three calls to create the promises but the resolve(), the jsonFlickrApiAsync() gets called only once.
What would be the right way to handle jsonP callbacks with Promise so I can have an Promise.all() to deal with the results as in the XmlHttpRequest version above?
No jQuery please - I want to understand whats really going
This is not a problem with promises, this is a problem with JSONP. Since it uses global callbacks, you need to use different callbacks - with different names - for each request. For Flickr that means you have to use their jsoncallback url parameter. The parameter name may vary for your actual endpoint.
However, your use of promises is indeed weird. Typically you'd use one promise per request, to represent that request's result. You are intentionally creating only one global promise, which cannot work.
function loadJSONP(url, parameter="callback") {
var prop = "loadJSONP.back" + loadJSONP.counter++;
var script = document.createElement("script");
function withCleanUp(r) {
return (x) => {
loadJSONP[prop] = null;
document.head.removeChild(script);
r(x);
}
}
return new Promise((resolve, reject) => {
loadJSONP[prop] = withCleanUp(resolve);
script.onerror = withCleanUp(reject);
// setTimeout(script.onerror, 5000); might be advisable
script.src = url+"&"+parameter+"="+prop;
document.head.appendChild(script);
});
}
loadJSONP.counter = 0;

Understanding jQuery.Deferred in the context of jQuey.AJAX (again)

I concede that, despite hours of reading and attempting, I am fundamentally unable to grasp something about Deferred promises and asynchrony in general.
The goal on my end is real, real simple: send some data to the server, and react to the contents of the response conditionally.
The response will always be a JSON object with save and error keys:
{ "save": true, "error":false}
// or
{ "save" : false,
"error" : "The server has run off again; authorities have been notifed."}
I have tried dozens and dozens of variations from the jQuery API, from other stackexchange answers, from tutorials, etc.. The examples all seem concerned with local asynchronous activity. When I need is some ability to be made aware when the AJAX request has either finished and returned a response I can inspect and make decisions about, or else to know that it's failed. Below, I've used comments to explain what I think is happening so someone can show me where I'm failing.
I know this is a repost; I am, apprently, worse than on average at grasping this.
var postData = {"id":7, "answer":"Ever since I went to Disneyland..."};
/* when(), as I understand it, should fire an event to be
responded to by then() when it's contents have run their course */
var result = $.when(
/* here I believe I'm supposed to assert what must complete
before the when() event has fired and before any chained
functions are subsequently called */
/* this should return a jqXHR object to then(), which is,
I'd thought, a queue of functions to call, in order,
UPON COMPLETION of the asynchronous bit */
$.post("my/restful/url", postData))
.then( function() {
/* since "this" is the jqXHR object generated in the $.post()
call above, and since it's supposed to be completed by now,
it's data key should be populated by the server's response—right? */
return this.data;
});
// alas, it isn't
console.log(result.data);
// >> undefined
Most examples I can find discuss a timeout function; but this seems, as I understand, to be a failsafe put in place to arbitrarily decide when the asynchronous part is said to have failed, rather than a means of stalling for time so the request can complete. Indeed, if all we can do is just wait it out, how's that any different from a synchronous request?
I'll even take links to a new read-mes, tutorials, etc. if they cover the material in a different way, use something other than modified examples from the jQuery API, or otherwise help this drooling idiot through the asynchronous mirk; here's where I've been reading to date:
jQuery API: Deferred
JQuery Fundamentals
jQuery Deferreds promises asynchronous bliss (blog)
StackOverflow: timeout for function (jQuery)
Update
This is in response to #Kevin B below:
I tried this:
var moduleA = {
var moduleB = {
postData: {"id":7, "answer":"Ever since I went to Disneyland..."};
save: function() {
return $.post("path/to/service", postData, null, "JSON");
}
};
var result = this.moduleB.save();
result.done(function(resp) {
if (resp.saved == true) {
// never reached before completion
console.log("yahoo");
} else {
console.log("Error: " + resp.error);
// >> undefined
}
});
}
You are over-complicating your code. You cannot get the data to outside of the callback, no matter how many deferred/promises you create/use (your sample creates 3 different deferred objects!)
Use the done callback.
var postData = {"id":7, "answer":"Ever since I went to Disneyland..."};
$.post("my/restful/url", postData).done(function (result) {
console.log(result.save, result.error);
});
You seem to have a misunderstanding of both asynchronous requests, the Promise pattern, and Javascripts mechanism of passing functions as an argument.
To understand what's really happening in your code I suggest you use a debugger and set some breakpoints in the code. Or, alternatively, add some console.logs in your code. This way you can see the flow of the program and might understand it better. Also be sure to log the arguments of the function you pass as an argument in the then()-method, so you understand what is passed.
ok you got it half right. the problem is that when you execute the console.log the promised is not yet fulfilled the asynchronous nature of the promises allows the code to execute before that ajax operation is done. also result is a deferred not a value, you need to handle your promised with .done instead of .then if you wish to return a value otherwise you'll continue passing promises.
so that said
var result={};
$.when(
$.post("my/restful/url", postData))
.done( function(data) {
result.data=data;
});
// here result is an object and data is a undefined since the promised has no yet been resolve.
console.log(result.data);

WinJS, return a promise from a function which may or may not be async

I have a situation where my WinJS app wants to call a function which may or may not be async (e.g. in one situation I need to load some data from a file (async) but at other times I can load from a cache syncronously).
Having a look through the docs I though I could wrap the conditional logic in a promise like:
A)
return new WinJS.Promise(function() { // mystuff });
or possibly use 'as' like this:
B)
return WinJS.Promise.as(function() { // mystuff });
The problem is that when I call this function, which I'm doing from the ready() function of my first page like this:
WinJS.UI.Pages.define("/pages/home/home.html", {
ready: function () {
Data.Survey.init().done(function (result) {
// do some stuff with 'result'
});
}
});
When it is written like 'A' it never hits my done() call.
Or if I call it when it's written like 'B', it executes the code inside my done() instantly, before the promise is resolved. It also looks from the value of result, that it has just been set to the content of my init() function, rather than being wrapped up in a promise.
It feels like I'm doing something quite basically wrong here, but I'm unsure where to start looking.
If it's any help, this is a slimmed down version of my init() function:
function init() {
return new WinJS.Promise(function() {
if (app.context.isFirstRun) {
app.surveyController.initialiseSurveysAsync().then(function (result) {
return new WinJS.Binding.List(result.surveys);
});
} else {
var data = app.surveyController.getSurveys();
return new WinJS.Binding.List(data);
}
});
}
Does anyone have any thoughts on this one? I don't believe the 'may or may not be async' is the issue here, I believe the promise setup isn't doing what I'd expect. Can anyone see anything obviously wrong here? Any feedback greatly appreciated.
Generally speaking, if you're doing file I/O in your full init routine, those APIs return promises themselves, in which case you want to return one of those promises or a promise from one of the .then methods.
WinJS.Promise.as, on the other hand, is meant to wrap a value in a promise. But let me explain more fully.
First, read the documentation for the WinJS.Promise constructor carefully. Like many others, you're mistakenly assuming that you just wrap a piece of code in the promise and voila! it is async. This is not the case. The function that you pass to the constructor is an initializer that receives three arguments: a completeDispatcher function, an errorDispatcher function, and a progressDispatcher function, as I like to call them.
For the promise to ever complete with success, complete with an error, or report progress, it is necessary for the rest of the code in the initializer to eventually call one of the dispatchers. These dispatchers, inside the promise, then loop through and call any complete/error/progress methods that have been given to that promise's then or done methods. Therefore, if you don't call a dispatcher at all, there is no completion, and this is exactly the behavior you're seeing.
Using WinJS.Promise.as is similar in that it wraps a value inside a promise. In your case, if you pass a function to WinJS.promise.as, what you'll get is a promise that's fulfilled with that function value as a result. You do not get async execution of the function.
To achieve async behavior you must either use setTimeout/setInterval (or the WinJS scheduler in Windows 8.1) to do async work on the UI thread, or use a web worker for a background thread and tie its completion (via a postMessage) into a promise.
Here's a complete example of creating a promise using the constructor, handling complete, error, and progress cases (as well as cancellation):
function calculateIntegerSum(max, step) {
if (max < 1 || step < 1) {
var err = new WinJS.ErrorFromName("calculateIntegerSum", "max and step must be 1 or greater");
return WinJS.Promise.wrapError(err);
}
var _cancel = false;
//The WinJS.Promise constructor's argument is a function that receives
//dispatchers for completed, error, and progress cases.
return new WinJS.Promise(function (completeDispatch, errorDispatch, progressDispatch) {
var sum = 0;
function iterate(args) {
for (var i = args.start; i < args.end; i++) {
sum += i;
};
//If for some reason there was an error, create the error with WinJS.ErrorFromName
//and pass to errorDispatch
if (false /* replace with any necessary error check -- we don’t have any here */) {
errorDispatch(new WinJS.ErrorFromName("calculateIntegerSum", "error occurred"));
}
if (i >= max) {
//Complete--dispatch results to completed handlers
completeDispatch(sum);
} else {
//Dispatch intermediate results to progress handlers
progressDispatch(sum);
//Interrupt the operation if canceled
if (!_cancel) {
setImmediate(iterate, { start: args.end, end: Math.min(args.end + step, max) });
}
}
}
setImmediate(iterate, { start: 0, end: Math.min(step, max) });
},
//Cancellation function
function () {
_cancel = true;
});
}
This comes from Appendix A ("Demystifying Promises") of my free ebook, Programming Windows Store Apps in HTML, CSS, and JavaScript, Second Edition (in preview), see http://aka.ms/BrockschmidtBook2.
You would, in your case, put your data initialization code in the place of the iterate function, and perhaps call it from within a setImmediate. I encourage you to also look at the WinJS scheduler API that would let you set the priority for the work on the UI thread.
In short, it's essential to understand that new WinJS.Promise and WinJS.Promise.as do not in themselves create async behavior, as promises themselves are just a calling convention around "results to be delivered later" that has nothing inherently to do with async.

Categories

Resources