最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to preserve the 'this' instance in a callback function - Stack Overflow

programmeradmin2浏览0评论

In Angular2 I have a ponent that uses a service for uploading a file to Amazon S3.

My ponent (simplified):

private _loading = true;

// use service to upload file
this._s3service.uploadFile(fileObject, this.uploadCallback)

// use this function as a callback
uploadCallback(err, data) {
  this._loading = false; // this crashes because of 'this' is referring to service instead of ponent
} 

My service (simplified):

    private getS3(): any {
       // Get or create AWS instance
       return s3;
    }

    public uploadFile(selectedFile, callback): boolean {
       this.getS3().upload({
            Key: key_name,
            ContentType: file.type,
            Body: file,
            StorageClass: 'STANDARD',
            ACL: 'private'
          }, function(err, data){ // <=== What to do here?!
            callback(err, data)
          });
    }

The problem is that when the callback function is fired from the service, this is referring to the service and this._loading cannot be found.

Question: How can I preserve the this instance in my callback function, (this in the callback must point to ponent and not service)

In Angular2 I have a ponent that uses a service for uploading a file to Amazon S3.

My ponent (simplified):

private _loading = true;

// use service to upload file
this._s3service.uploadFile(fileObject, this.uploadCallback)

// use this function as a callback
uploadCallback(err, data) {
  this._loading = false; // this crashes because of 'this' is referring to service instead of ponent
} 

My service (simplified):

    private getS3(): any {
       // Get or create AWS instance
       return s3;
    }

    public uploadFile(selectedFile, callback): boolean {
       this.getS3().upload({
            Key: key_name,
            ContentType: file.type,
            Body: file,
            StorageClass: 'STANDARD',
            ACL: 'private'
          }, function(err, data){ // <=== What to do here?!
            callback(err, data)
          });
    }

The problem is that when the callback function is fired from the service, this is referring to the service and this._loading cannot be found.

Question: How can I preserve the this instance in my callback function, (this in the callback must point to ponent and not service)

Share Improve this question edited Mar 17, 2017 at 10:10 Vingtoft asked Mar 17, 2017 at 9:45 VingtoftVingtoft 14.7k26 gold badges91 silver badges145 bronze badges 1
  • Possible solution might also be using Instance function github./Microsoft/TypeScript/wiki/… – yurzui Commented Mar 17, 2017 at 10:08
Add a ment  | 

3 Answers 3

Reset to default 11

Use arrow functions

  }, (err, data) => { // <=== What to do here?!

they are for exactly that purpose, for this to keep pointing at the class instance where the function is declared.

https://developer.mozilla/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

If you pass a function reference .bind(this) might be more convenient, because it doesn't require to list the parameters at all while => would require them twice

myCallback(err, data){ // <=== What to do here?!
        callback(err, data)
}

public uploadFile(selectedFile, callback): boolean {
   this.getS3().upload({
        Key: key_name,
        ContentType: file.type,
        Body: file,
        StorageClass: 'STANDARD',
        ACL: 'private'
      }, this.myCallback.bind(this));
}

The same which arrow functions

public uploadFile(selectedFile, callback): boolean {
   this.getS3().upload({
        Key: key_name,
        ContentType: file.type,
        Body: file,
        StorageClass: 'STANDARD',
        ACL: 'private'
      }, (err, data) => this.myCallback(err, data));
}

While @Gunter is right, I think you want to keep the this in the callback you actualy pass to that function :

uploadCallback(err, data) {
  this._loading = false; // this is the "this" you want to keep
} 

then it would be something like this:

this._s3service.uploadFile(fileObject, ()=>this._loading = false);
// or 
this._s3service.uploadFile(fileObject, ()=>this.uploadCallback());
// or
this._s3service.uploadFile(fileObject, this.uploadCallback.bind(this));

Also note that it might be interesting to use an Observable instead of passing a callback :

public uploadFile(selectedFile): Observable<any> { // "<any>" because I don't know what is the type of "data"
    return Observable.create((observer) => {
        this.getS3().upload({
            Key: key_name,
            ContentType: file.type,
            Body: file,
            StorageClass: 'STANDARD',
            ACL: 'private'
        }, (err, data)=> {
            if(err)
              observer.error(err);
            else
              observer.next(data);
            observer.plete();
        });
    });
}

then:

this._s3service.uploadFile(fileObject).subscribe(data=>console.log(data))

You could change your uploadFile to return a promise.

and handle the error case from your ponent as it should be. Something like

    public uploadFile(selectedFile): boolean {
        return new Promise((resolve, reject) => {
          this.getS3().upload({
            Key: key_name,
            ContentType: file.type,
            Body: file,
            StorageClass: 'STANDARD',
            ACL: 'private'
         }, function(err, data){ // <=== What to do here?!
            resolve(err, data)
        });
       }
  });

And you could from your ponent do this

 this._s3service.uploadFile(fileObject).then((err, data)=> {
   this._loading = false;
 });
发布评论

评论列表(0)

  1. 暂无评论