Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebSocket callback within arrow function not setting 'this' lexically

I am trying to create a WebSocket service in Angular 2. Here is what I have so far:

import {Injectable} from "angular2/core"
@Injectable()
export class ServerService {

    public ws:WebSocket;

    public myData = {};

    constructor() {
        let ws = new WebSocket('ws://localhost:8080/');

        ws.onopen = (event:Event) => {
            console.log("Socket has been opened!");
        };

        ws.onmessage = (event:Event) => {
            this.myData = JSON.parse(event.data);
        };
    };
}

The problem is, when onmessage runs, the this keyword becomes the WebSocket object, instead of my ServerService object.

It seems like my arrow function is acting as a standard function. What could be causing this? Is there another way to get back to the ServerService object?

like image 359
Daniel Stafford Avatar asked May 07 '16 04:05

Daniel Stafford


People also ask

Can we use this keyword in Arrow function?

b) Arrow Function These were introduced in ES6. Their concise syntax and handling of the this keyword has made JavaScript arrow functions an ES6 favourite among developers. If there are no parameters, then you can place empty parentheses before => like the below example.

Which is the correct arrow function to add two numbers?

As you can see, (a, b) => a + b means a function that accepts two arguments named a and b . Upon the execution, it evaluates the expression a + b and returns the result. If we have only one argument, then parentheses around parameters can be omitted, making that even shorter.

What is the arrow function in JavaScript?

Arrow function is one of the features introduced in the ES6 version of JavaScript. It allows you to create functions in a cleaner way compared to regular functions. For example, This function // function expression let x = function(x, y) { return x * y; }


2 Answers

OK, so after seeing Abdulrahmans example working in plunk, I figured there was probably something wrong with my environment. Turns out my TypeScript was compiling to ES5, and was outputting:

function ServerService() {
                var _this = this;
                this.myData = {};
                var ws = new WebSocket('ws://localhost:8080');
                ws.onopen = function (event) {
                    console.log("Socket has been opened!");
                };
                ws.onmessage = function (event) {
                    _this.myData = JSON.parse(event.data);
                };
            }

My arrow functions were indeed being removed, but replaced with something that should(?) be functionally equivalent. It works as expected in Firefox, but not in Chrome (which is where I was debugging).

I switched my TypeScript compiler to output ES6, and now I have arrow functions in my JavaScript, and my code works as expected in both browsers.

like image 136
Daniel Stafford Avatar answered Oct 18 '22 18:10

Daniel Stafford


I fixed it using Function.prototype.bind(), which is only available on oldschool anonymous functions, not arrow functions.

So instead of:

ws.onmessage = (event:Event) => {
    this.myData = JSON.parse(event.data);
};

I did:

ws.onmessage = function(event:Event) {
    this.myData = JSON.parse(event.data);
}.bind(this);
like image 21
Sámal Rasmussen Avatar answered Oct 18 '22 18:10

Sámal Rasmussen