I have a typescript app that it is mixing 'this' context inside a class.
This class is responsible to setup new Express server instance.
If I track 'this' with debugger and node --inspect-brk
we can see 'this' is undefined when serverProtocol gets resolved but it does not matter !
I've setup a little project to show what i'm facing.
$> git clone https://github.com/AdSegura/ThisLoseContext.git
$> cd ThisLoseContext/
$> npm i
$> npm run build && node dist/
INIT: Server_ID: quijote_1111, PORT: 1111
-----------------------------------------
INIT: Server_ID: quijote_2222, PORT: 2222
-----------------------------------------
Callback: Server_ID: quijote_1111, PORT: 1111
ServerProtocol: Server_ID: quijote_1111; PORT: 1111
Callback: Server_ID: quijote_2222, PORT: 2222
ServerProtocol: Server_ID: quijote_2222; PORT: 2222
INIT: Server_ID: quijote_1111, PORT: 1111
-----------------------------------------
INIT: Server_ID: quijote_2222, PORT: 2222
-----------------------------------------
Callback: Server_ID: quijote_1111, PORT: 2222 [ERROR]
ServerProtocol: Server_ID: quijote_1111; PORT: 2222 [ERROR]
Callback: Server_ID: quijote_2222, PORT: 2222
ServerProtocol: Server_ID: quijote_2222; PORT: 2222
The problem is in Server.ts this.serverProtocol()
is mixing this.options.port
var http = require('http');
var express = require('express');
const os = require("os");
export class Server {
/** The http server.*/
public express: any;
/** express httpServer */
protected server: any;
/** id representing server instance */
protected server_id: any;
/**
* Create a new server instance.
*/
constructor(private options: any) {
this.server_id = this.generateServerId();
}
/**
* Start the Socket.io server.
*
* @return {void}
*/
init(): Promise<any> {
console.log(`INIT: Server_ID: ${this.server_id}, PORT: ${this.options.port}`);
return new Promise((resolve, reject) => {
debugger;
this.serverProtocol().then(instance => {
debugger;
console.log(`ServerProtocol: Server_ID: ${this.server_id}; PORT: ${this.options.port}`);
resolve();
}, error => reject(error));
});
}
/**
* Select the http protocol to run on.
*
* @return {Promise<any>}
*/
serverProtocol(): Promise<any> {
return this.httpServer()
}
/**
* Express socket.io server.
*/
httpServer(): Promise<any> {
return new Promise((resolve, reject) => {
this.express = express();
this.express.use((req, res, next) => {
for (var header in this.options.headers) {
res.setHeader(header, this.options.headers[header]);
}
next();
});
const httpServer = http.createServer(this.express);
function cb() {
debugger;
console.log(`Callback: Server_ID: ${this.server_id}, PORT: ${this.options.port}`)
return resolve.call(this, this)
}
this.server = httpServer.listen(this.options.port, this.options.host, () => cb.call(this));
})
}
/**
* Generate Server Id
*
* @return string hostname_port
*/
generateServerId(): string {
const hostname = os.hostname();
const port = this.options.port;
return `${hostname}_${port}`
}
}
I'm a novice with typescript, I tried multiple targets at tsconfig but same result, this.options
gets the last config {port:2222}
when you instanciate two or more objects.
Thanks.
I think understand this:
There is no such thing as a "local object". You do have a reference to an object. Two instances might have two references to the same object.
const opt = { foo: 3 };
export class MyClass {
constructor(private options: any){
this.options = Object.assign(opt, options)
}
getOptions(): any {
return this.options
}
}
export class MyClass {
constructor(private options: any){
const opt = { foo: 3 };
this.options = Object.assign(opt, options)
}
getOptions(): any {
return this.options
}
}
But as our partners said bellow, the safest methods to create new options variable are:
this.options = Object.assign({}, this.defaultOptions, config);
or
this.options = { ...this.defaultOptions, ...config };
And now we have a new object not a copy to an object outside the scope of the constructor method.
So the safest version of the code should be:
export class MyClass {
constructor(private options: any){
const opt = { foo: 3 };
this.options = Object.assign({}, opt, options)
}
getOptions(): any {
return this.options
}
}
The issue is probably inside the EchoServer
class, namely here:
this.options = Object.assign(this.defaultOptions, config);
Thats equal to:
this.options = this.defaultOptions;
Object.assign(this.defaultOptions, config);
I assume you actually wanted to do:
this.options = Object.assign({}, this.defaultOptions, config);
which creates an own options
object for each instance.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.