Angular 5中Google API Promise回调this指向异常及解决
问题:调用Google API Promise时
this.youtube未定义,自定义Promise却正常工作 问题描述
你遇到的情况是:自己编写的Promise能正常修改组件的name属性,但调用Google API的Promise时,却报错提示this.youtube未定义,无法更新该属性。
相关代码
index.html
<script src="https://apis.google.com/js/api.js"></script>
app.component.html
<button (click)="customClick()">custom Promise</button> <hr> <hello name="{{ youtube }}"></hello> <button (click)="youtubeClick()">youtube Promise</button>
app.component.ts
import { Component } from '@angular/core'; import { } from '@types/gapi.client.youtube'; import { } from '@types/gapi.auth2'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { name = 'Angular 5'; youtube = 'youtube'; egPromise(){ return new Promise<void>((resolve, reject) => { setTimeout(function(){ resolve(); }, 1000); }); } customPromise(){ this.egPromise().then( () => { this.name = 'from .then angular 5' }); } customClick(){ this.customPromise(); } // Google API相关逻辑 youtubePromise(){ gapi.client.init({ apiKey: 'key', clientId: 'id', scope: "https://www.googleapis.com/auth/youtube.readonly", discoveryDocs: [ "https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest" ] }).then(() => { this.youtube = 'from .then youtube' }); } youtubeClick(){ gapi.load('client:auth2', this.youtubePromise); } }
问题根源
当你直接把this.youtubePromise作为回调传给gapi.load时,函数的this上下文会被改变——此时this不再指向你的AppComponent实例,而是指向调用这个回调的gapi内部对象,自然就找不到this.youtube这个组件属性了。
反观你的自定义Promise能正常工作,是因为在customPromise的then回调里用了箭头函数,箭头函数不会创建自己的this,它会继承外层作用域的this(也就是AppComponent实例),所以能正确访问this.name。
解决方案
这里有两种简单的修复方式:
方法1:用箭头函数包裹回调调用
修改youtubeClick方法,通过箭头函数来调用youtubePromise,这样就能保留正确的this上下文:
youtubeClick(){ gapi.load('client:auth2', () => this.youtubePromise() ); }
箭头函数会沿用外层(AppComponent实例)的this,所以在youtubePromise里的this依然指向组件实例,就能正常修改this.youtube了。
方法2:提前绑定this到回调函数
也可以用bind方法把this固定到youtubePromise上,再传递给gapi.load:
youtubeClick(){ gapi.load('client:auth2', this.youtubePromise.bind(this) ); }
bind(this)会返回一个新函数,这个函数的this会永久绑定为AppComponent实例,调用时就不会出现上下文丢失的问题了。
内容的提问来源于stack exchange,提问作者Mateus Silva
相关产品推荐
相关产品推荐

