JavaScript - Using "this" with chained promises [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
I am writing some Node code with ES6. In my code, I have a class, that looks like the following. Please note, this is a basic example intended to isolate and show the problem.
class MyClass {
constructor() {
this.id = uuid();
this.number = Math.floor((Math.random() * 100) + 1);
}
process() {
this.validateNumber()
.then(this.generateImage)
.catch(function(err) {
console.log(err);
})
;
}
validateNumber() {
let self = this;
var promise = new Promise(function(resolve, reject) {
// do stuff with self.number
resolve({});
});
}
generateImage() {
console.log(this);
// the above prints "undefined" in the console window
// how do I get this.number again?
}
}
In this class, you'll notice that I generate a random number in my constructor. I want that number to be usable throughout the methods in my class. However, since I have one method that chains together promises, it's like this loses meaning after validateNumber is executed.
how do I resolve this?

ES6 introduced a feature called arrow functions. Apart from the syntax being more concise than the conventional function syntax, it retains the context of this. Essentially, your code can be changed to the following:
var promise = new Promise((resolve, reject) => {
console.log(this); // MyClass
resolve({});
});
And you also need to retain the context inside the then
this.validateNumber()
.then(() => this.generateImage());

Related

Can't Access Class Property From Delegate Function [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
Long-time .Net developer here, tasked with converting a bunch of old JS code to new ES6 JS modules. I'm trying to run the (you would think) simple code below, but when jumpToVideoNew is called, this.allowVidJump in the delegate function doesn't have access to the class property allowVidJump. I'm trying to set a simple timed delay so calling code can't hammer the jumpToVideoNew function repeatedly. I understand the concept that the variable loses scope, but I've tried setting _this = this; and using _this in the delegate as well with no success. Also tried passing a reference to the variable in to the function and accessing it that way, but also no luck. Spending 2 hours on something this simple is reminding me why I steer clear of javascript when possible.
export class WebUtility {
constructor() {
this.allowVideoJump = true;
this.delay = function () { this.allowVidJump = true; };
}
jumpToVideoNew() {
if (this.allowVideoJump) {
this.allowVideoJump = false;
setTimeout(this.delay, 1000);
}
}
}
Use an anonymous arrow function
The function keyword in JS creates a new scope as well as a new this (the function you just defined === this), so this.allowVidJump is essentially (function() {}).allowVidJump in that scope
Try something like this:
export class WebUtility {
constructor() {
this.allowVideoJump = true;
this.delay = () => { this.allowVidJump = true; }; // anonymous lambda
}
jumpToVideoNew() {
if (this.allowVideoJump) {
this.allowVideoJump = false;
setTimeout(this.delay, 1000);
}
}
}

this context lost when passing a reference to a method [duplicate]

This question already has answers here:
Pass correct "this" context to setTimeout callback?
(6 answers)
Closed 6 years ago.
In this example
class Car {
describe() {
console.log("I have " + this.wheels);
}
testMe() {
setTimeout( this.describe, 1000);
}
constructor(wheels) {
this.wheels = wheels;
}
}
let myCar = new Car(4);
myCar.testMe(); // I have undefined
How come the expected value of this isn't passed inside the describe function ?
edit : Can you confirm that is setTimeout was an arrow function, I wouldn't get undefined ?
A bare function reference has no context, even if it was retrieved as a property of an object.
Within your testMe function you need either:
setTimeout(() => this.describe(), 1000);
or
setTimeout(this.describe.bind(this), 1000);
or
let self = this;
setTimeout(function() {
self.describe();
}, 1000);
That last one could be written as an arrow function, of course, but if you're doing that you might as well use the first version, with no local copy of this required.
Regarding your edit, it is possible to pass just this.describe by making describe an arrow function, assigned from inside the constructor, but note that this then means that every instance of the object would have its own copy of that function instead of there just being a single copy on the prototype of the class:
constructor(wheels) {
this.wheels = wheels;
this.describe = () => {
console.log("I have " + this.wheels);
}
}

difference between (callback) and (() => callback()) in typescript (angular2) [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
Normally I'd assign an alternative "self" reference when referring to "this" within setInterval. Is it possible to accomplish something similar within the context of a prototype method? The following code errors.
function Foo() {}
Foo.prototype = {
bar: function () {
this.baz();
},
baz: function () {
this.draw();
requestAnimFrame(this.baz);
}
};
Unlike in a language like Python, a Javascript method forgets it is a method after you extract it and pass it somewhere else. You can either
Wrap the method call inside an anonymous function
This way, accessing the baz property and calling it happen at the same time, which is necessary for the this to be set correctly inside the method call.
You will need to save the this from the outer function in a helper variable, since the inner function will refer to a different this object.
var that = this;
setInterval(function(){
return that.baz();
}, 1000);
Wrap the method call inside a fat arrow function
In Javascript implementations that implement the arrow functions feature, it is possible to write the above solution in a more concise manner by using the fat arrow syntax:
setInterval( () => this.baz(), 1000 );
Fat arrow anonymous functions preserve the this from the surrounding function so there is no need to use the var that = this trick. To see if you can use this feature, consult a compatibility table like this one.
Use a binding function
A final alternative is to use a function such as Function.prototype.bind or an equivalent from your favorite Javascript library.
setInterval( this.baz.bind(this), 1000 );
//dojo toolkit example:
setInterval( dojo.hitch(this, 'baz'), 100);
i made a proxy class :)
function callback_proxy(obj, obj_method_name)
{
instance_id = callback_proxy.instance_id++;
callback_proxy.instances[instance_id] = obj;
return eval('fn = function() { callback_proxy.instances['+instance_id+'].'+obj_method_name+'(); }');
}
callback_proxy.instance_id = 0;
callback_proxy.instances = new Array();
function Timer(left_time)
{
this.left_time = left_time; //second
this.timer_id;
this.update = function()
{
this.left_time -= 1;
if( this.left_time<=0 )
{
alert('fin!');
clearInterval(this.timer_id);
return;
}
}
this.timer_id = setInterval(callback_proxy(this, 'update'), 1000);
}
new Timer(10);

What's difference between promise then and binding in AngularJS? [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I am wondering what is difference between those two services in AngularJS. In both there is promise and basicly both works.
Method with self variable:
module.exports = function () {
var self = this,
data = false;
self.someFunction = function () {
methodFromAnotherService().then(function (reponse) {
data = response;
});
};
};
Method with binding:
module.exports = function () {
var data = false;
this.someFunction = function () {
methodFromAnotherService().then(function (reponse) {
data = response;
}.bind(this));
};
};
The secound one doesn't work without binding. I know that this have something to do with scope. Please provide any usefull information about major differences.
The Promise object is used for deferred and asynchronous computations. A Promise represents an operation that hasn't completed yet, but is expected in the future.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind

"this" is undefined when function is passed as argument in chain [duplicate]

This question already has answers here:
Object method with ES6 / Bluebird promises
(2 answers)
Closed 7 years ago.
Simple example of my problem
Consider the following situation, where I have a few functions (a and b) that I used in a promise-chain in c:
class SomeClass {
constructor(){
this.v1 = 1;
this.v2 = 2;
}
a() {
return new Promise((resolve, reject) => {
console.log('a', this.v1); // Do something with `this`
resolve();
});
}
b() {
return new Promise((resolve, reject) => {
console.log('b', this.v2); // Do something with `this`
resolve();
});
}
c() {
return this.a().then(this.b); // passing b as argument
}
}
When I call c and run the chain of promises, this is undefined in b.
const sc = new SomeClass();
sc.c().then(() =>{
console.log('done')
}).catch((error) => {
console.log('error', error);
});
Output:
a 1
error [TypeError: Cannot read property 'v2' of undefined]
I know that arrow functions inherit the outer this, but I am not sure why it is undefined since I am invoking it from c.
The problem is here:
this.a().then(this.b)
because the resulting function retrieved by this.b becomes unbound from this (you don't actually invoke it in the way stated in your question).
You can solve it in a way that is consistent with the rest of your code, by using an arrow method to preserve scope:
this.a().then(obj => this.b(obj))
or you can use .bind to achieve a similar result:
this.a().then(this.b.bind(this))

Categories