How do I create an observable from the onmessage callback? - javascript

I am fairly used to RX having used it in .NET and Java, I am expecting to be able to do the following:
Rx.Observable.fromCallback(websocket.onmessage)
.map(...)
.subscribe(...);
however, the console has the following:
Uncaught TypeError: Rx.Observable.fromCallback(websocket.onmessage).map is not a function
which would appear to indicate that the fromCallback is not returning an Observable.
What am I doing wrong here? Have I misunderstood what fromCallback is doing and I need to use a Subject? Can I not wrap some arbitrary handler in an observable?

You are actually looking for fromEvent or fromEventPattern:
Rx.Observable.fromEvent(websocket, 'message').map(/*...*/).subscribe();
Rx.Observable.fromEventPattern(
function add(h) { websocket.addEventListener(h); },
function remove(h) { websocket.removeEventListener(h); })
.map(/*...*/)
.subscribe();
The first one will attempt to use some of the standard ways of subscribing to an event emitter, which WebSocket is. However, if that fails you can use fromEventPattern instead to specify how handlers are added or removed from your object.
One additional note, JavaScript does not pass along an implicit reference to the instance of the object you are using as C# and Java do, so your code fromCallback(websocket.onmessage) is not passing along websocket, it is passing along the reference to the method from the function prototype. this will be determined at execution time.
Rx.Observable.fromCallback is for functions whose last argument is a callback function which is a standard pattern for asynchronous JavaScript code. Further, the fromCallback method does not return an Observable it returns a function that when called returns an Observable i.e.
function methodWithCallback(arg0, arg1, cb) {
setTimeout(function() {
cb(arg0 + arg1);
}, 2000);
}
var newMethod = Rx.Observable.fromCallback(methodWithCallback);
//[After 2 seconds] 3
newMethod(1, 2).subscribe(console.log.bind(console));

Related

How does that implicit passing of function arguments in Javascript work?

I am originally coming from Java programming language as background. Java is strongly typed and quite explicit (I mean by that, you have to write things out, you can't just omit them). One thing, that will never get in my head is how that implicit parameter passing to javascript works...
as an example:
const observer = {
next: console.log,
error: console.error,
test: console.table,
}
observer.next('HI World!')
in next, I specify console.log which is a function, but I never say to accept a value, but in Javascript I apparently can just throw anything to functions as suffix and it takes that as an argument to its function.
Thats also how pipelining or currying basically works, it takes the remaining return values as parameters..why is that so?
Secondly, e.g in express, I have a function signature like so:
app.get('/', function (req, res) {
res.send('GET request to the homepage');
});
I actually get req and res out of my function callback is that right? those are not parameters that I pass to my callback function?
Edit: Can someone explain to me again where the REQand RES parameters are coming from? How does that construct work? Because I am defining the callback function myself, but instead of passing req and res as parameters to my callback, it seems they get passed from somewhere back to inside my callback function?!?!
A function in JavaScript is an object just like any other. This means a function can be passed around, can be assigned to variables, and essentially can be used anywhere a value can be used. This is known as first-class functions.
For example, given a simple function like this one:
function log(msg) {
console.log(msg);
}
These two functions are conceptually equivalent:
const log1 = log;
// same as
function log1(msg) {
log(msg);
}
As you can see, we can directly assign the function log to a variable like log1, ,and then we can use log1 just like we use log:
log1('foobar');
Another usage of first-class functions is to be able to pass them as arguments to other functions. A function that takes a callback like in your Express example is known as a higher-order function. The arguments of the callback are provided by the caller of that callback. In your case Express provides the req and res arguments.
Using callbacks is a form of inversion of control. You are passing control of that part of the program to the caller.

Pass multiple parameters within Promises

I want to pass the previously resolved, returned data and an additional parameter within a promise chain. See the example for clarification.
Below functions both return a Promise and are properly executed. It's really just about passing additional parameter.
Lets consider a Promise chain like:
API.getSomething(id).then(API.processIt)
getSomething function(id) { returns a promise with data }
processIt function(data) { process the returned data }
With a syntax like above it works fine. Once I add additional parameter:
API.getSomething(id).then(API.processIt(data, "random"))
processIt function(data, misc) {...} it does't work anymore.
Is there a way to pass additional parameters within a Promise chain using the result of the previous executed Promise without any additional library?
It's not about the design of the whole chain. I know, the problem could be bypassed with a different design but due to changes in some APIs that's the way I have to handle with the problem.
On this line
API.getSomething(id).then(API.processIt(data, "random"))
You are trying to pass function as reference but you are invoking the function instead.
Try
API.getSomething(id).then(function(data){
API.processIt(data, "random");
});

Resolve value in javascript

I have the following code:
function doSomething() {
//xhr here
setTimeout(function() {
var value = 42;
}, 10);
return {
then: function(callback) {
callback(value);
}
};
}
doSomething().then(function(result) {
log("got a result", result);
});
And can't figure out how to access the value.
I need this to be promise-based solution in order to use in multiple places
JSFidle link
Update:
We are not using any libraries in that projects
There are a couple of problems there:
value is local to the function you're passing into setTimeout, because that's where you've declared it. You could fix this issue by declaring it in doSomething instead.
The bigger issue is that what you have there isn't a promise, it's just a function that returns an object when you call it that has a then method. Here's the order in which things happen:
You call doSomething
It sets a timer to set a value.
It creates an object with a then function.
It returns the object.
You call the then function immediately.
then tries to access value (which it can't because of the declaration issue, but would be a problem anyway).
Some time later, value is set by the callback when the timer fires.
To be a promise, the then function on object you return would have to store a reference to the callback passed into it, and call the callback later, when value has been set (e.g., the promise has been fulfilled).
Rather than implementing your own promises library, I'd suggest using one of the several that have already been written and debugged.
I'm just pointing out, that in order to "fix" your issue you need to return the then this way:
function doSomething() {
//xhr here
return {
then: function(callback) {
setTimeout(function() {
callback(42); // callback from within the async action
}, 10);
}
};
}
doSomething().then(function(result) {
log("got a result", result);
});
Please read TJ's answer and consider using a promise library - also consider reading this post that explains how promise resolution looks like.
Namely: Your then needs to in turn return a promise when called (rather than just set a timeout) for chaining, and the callback should be assimilated before waiting for it.

When I use a method as a callback, it seems to lose access to `this`. Why?

I'm using express in Node to create a simple web app. The code looks like this:
var get_stuff = function (callback) {
another.getter(args, function (err, data) {
if (err) throw err;
data = do_stuff_to(data);
callback(data);
});
};
app.get('/endpoint', function (req, res) {
get_stuff(res.send);
});
When I run this, though, I get this error: TypeError: Cannot read property 'method' of undefined at res.send. The express code that's breaking starts like this:
res.send = function (body) {
var req = this.req;
var head = 'HEAD' == req.method;
It seems to me that the way I've constructed the callbacks is losing this in the send method. But I'm not sure how to fix it. Any tips? Thanks!
Call .bind:
get_stuff(res.send.bind(res));
and have a look at the MDN documentation about this to get an idea how it works. The value of this is determined by how the function is called. Calling it "normally" (what probably happens with the callback), like
func();
will set this to the global object. Only if a function is called as an object method (or if this is explicitly set with .bind, .apply or .call are used), this refers to the object:
obj.fun(); // `this` refers to `obj` inside the function
.bind allows you to specify the this value without calling the function. It simply returns a new function, similar to
function bind(func, this_obj) {
return function() {
func.apply(this_obj, arguments);
};
}
In JavaScript, the value of this is generally determined by the call site, and unlike in Python, accessing a method via the . operator does not bind its left-hand side to this when the method is later called.
To perform the binding, you can call .bind like in the older answer, or you may perform the binding by hand, wrapping the method call in another callback:
get_stuff(function () {
return res.send.apply(res, arguments);
});
As of ECMAScript 2018, it’s also possible to use fat-arrow function syntax and rest parameters to make the above much more compact:
get_stuff((...args) => res.send(...args));

What is 'result' in Win8 JS code: WinJS.xhr({urlhere}).done(function complete(result) { });

See the following line of code:
WinJS.xhr({ url: "http://someurl.com" }).then(
function fulfilled(result)
{
if (result.status === 200)
{
resDiv.style.backgroundColor = "lightGreen";
resDiv.innerText = "Success";
}
});
As far as I understand, when WinJS.xhr has completed whatever it does then execute the anonymous function 'fulfilled' with argument 'result'
Coming from Java/C++ background, I'm extremely confused with how this code works - how is 'result' being passed to this function? Where does it say anything about what 'result' is? How can I know what type of object 'result' is and how it has a 'status' member?
I'm going to break my answer into two parts: The first concerns the actual execution model of Javascript, and the second which concerns the high-level expression as written.
The Javascript Execution Model
WinJS evaluates to an object.
That object has a prototype which contains an xhr member which WinJS.xhr evaluates to. That member is a function, which we will refer to as A below so that we can keep clear what exactly is going on.
Before we get to that, { url: "http://someurl.com" } returns an object which we will refer to as B.
That object B has a property called url.
A(B) calls a function A with a value B as an argument. It returns an object that we will refer to as C.
That object C has a prototype which contains a member named then. C.then happens to evaluate to a function. That function we will refer to as D.
function fulfilled(result) {...} returns a function that we will refer to as E. It can also be referred to as fulfilled but that fact is not used in this program fragment.
D(E) calls a function D with a value E as an argument. Nothing is done with the return value.
The high-level view
There are three functions here; one is a callback (called fulfilled), and the other two may be called "methods"- one xhr of the WinJS global object, and then of a promise object.
WinJS.xhr({ url: "http://someurl.com" }) creates and returns that promise object. You can convince yourself of this by consulting the documentation.
The promise object has a method called then which registers what you can think of as an event handler for when the promise is done. The value result - used in that callback registered in then comes from whatever is making that promise done by in fact calling the method done on that promise. You don't see the code that does that because it's someplace in the implementation of WinJS.xhr.
What WinJS.xhr is doing is performing a network request. When that network request is done it will signal the result of that network request (which according to the documentation is an XMLHttpRequest object) through the promise by calling the done() method on that promise. That in-turn calls the callback we registered with the then() method.
The documentation for the WinJS functions is still not great, IMO. You can look at the documentation for WinJS.xhr at http://msdn.microsoft.com/en-us/library/windows/apps/br229787.aspx, and that will give you some information on that - it says that the xhr function "wraps ... XMLHttpRequest object in a promise". Personally I've found it easier to look at the examples / quickstarts than at the reference documentations.
What you have passed to the fulfilled function (or the first function there) isn't the "result" of the operation, but the XMLHttpRequest object itself. On that you can get its properties to see the result - take a look at http://msdn.microsoft.com/en-us/library/windows/apps/ms535874.aspx for its reference.
The xhr method returns a Promise object, which has the then method that takes the onComplete, onError and onProcress callback functions.
This code only uses the onComplete callback. The callback is called when the request is completed, and it's sent a parameter with the value sent from the server.
If you are not familiar will callback functions, it may be clearer if you declare a regular function an use as the callback:
function fulfilled(result) {
if (result.status === 200) {
resDiv.style.backgroundColor = "lightGreen";
resDiv.innerText = "Success";
}
}
WinJS.xhr({ url: "http://someurl.com" }).then(fulfilled);
The then method is intended for pre-processing the result, you should rather use the done method to take care of the result.
I haven't found anything in the documentation that specifies exactly in what form the value comes from the server. It's probably there somewhere, but as usual with Microsoft documentation, it's rather complete but everything isn't everywhere so you have to look in different places to find specific information.

Categories

Resources