【问题标题】:Typescript 'await' doesn't appear to wait?打字稿'等待'似乎没有等待?
【发布时间】:2019-03-12 18:27:49
【问题描述】:

请原谅 noobie 错误,我正在尝试来自 C# 背景的 Ionic,因此这可能是问题的一部分。 我正在尝试从 Ionic 存储中获取存储的令牌,但我很难理解承诺,因此决定使用“等待”,因为我在 c# 中已经习惯了。

这是我要构建的 Api 服务的一部分,因此需要按顺序获取我的 http 标头,因此在构造函数中我检索令牌以将其添加。 下面是一段Api服务TS文件:

      export class ApiService {

    ServerUrl = environment.url;
    BearerToken: string;
    GetUserDetailsEndPoint = 'api/Account/GetUserDetails';
    UpdateUserDetailEndPoint = 'api/Account/UpdateUserDetail';
    TokenEndPoint = 'Token';
    RegisterEndPoint = 'api/Account/Register';
    httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Authorization': 'bearer ' + this.BearerToken
      })
    };

      constructor( private http: HttpClient,
      private storage: Storage,
      private alertController: AlertController ) {

      this.getBearerToken();    // I put this in a function cos not sure how the async stuff plays out in a constructor
      console.log('Have awaited the token and its value is:' + this.BearerToken);
    }

    async getBearerToken()  {
      this.BearerToken = await this.storage.get(TOKEN_KEY);
    }

很简单,“this.BearerToken”在发送到控制台时是未定义的。 (该值确实存在于商店中)。 它显然是某种异步类型的问题,但我很难理解为什么“等待”没有..? 我已经阅读了很多,但大多数时候人们都在使用带有 promise 的 .then 功能。我在这里想念什么? 谢谢

编辑 在这里听取了 Igor 的建议后,我将初始化从 UserService 移到了我的菜单页面的 ngOnInit 中,这是我首先需要使用它的地方。我在从本地存储而不是令牌获取用户信息的同一领域内,但这是同一个问题。 所以我想我仍然无法理解一些东西......获取存储用户的功能是这样的:

    async getUserStore() { // Populate the data object with the stored info
    this.data = await this.storage.get(USER_DATA);
    console.log('getUserStore: email = ' + this.data.Email);

    }

其中 this.data 是服务类中的 UserData 对象。 然而,这个函数仍然返回一个promise,而不是在返回之前等待。我是否需要让它返回一些特定的东西才能让 await 真正等待?例如

        return await this.storage.get(USER_DATA);

或使用 .then 方法,如果是,那么“等待”它的意义何在?

我的调用函数如下所示:(按预期工作)

  ngOnInit() {
this.user.getUserStore().then(() => {
  console.log('ngOnInit - menu page, this.user email is: ' + this.user.data.Email);
  if (this.user.data && !this.user.data.DetailsComplete) {
    this.showAlert('Your Details are incomplete, please can you complete them?');
  }
  console.log('ngOnInit - menu page');
});

}

而异步函数中的 await 我希望它看起来像这样:(这不起作用)

  ngOnInit() {
this.user.getUserStore();
console.log('ngOnInit - menu page, this.user email is: ' + this.user.data.Email);
if (this.user.data && !this.user.data.DetailsComplete) {
  this.showAlert('Your Details are incomplete, please can you complete them?');
}
console.log('ngOnInit - menu page');

}

那么我如何(使用等待)让它在被调用函数中真正等待?还是不能? 干杯

【问题讨论】:

  • 你没有在构造函数中等待调用this.getBearerToken();。出于其他原因,您不应该在构造函数中执行异步操作,但这就是尚未完成的原因。

标签: angular typescript ionic-framework


【解决方案1】:

不要在constructor 中调用async/await,因为构造函数不支持async/await 关键字。如果你想使用async/await,你应该确保所有Promises都被等待或使用then()等方法解决,如果你确实使用async/await,则使用@987654328的方法@ call(s) 的签名以 async 为前缀。

将“复杂”逻辑放入构造函数的设计缺陷之一是您的类型变得难以进行单元测试。在这种情况下,另一个是您不能使用关键字await,因为您不能将构造函数标记为async

选项 1 - 提供标记为 async/await 的新方法

constructor( private http: HttpClient,
    private storage: Storage,
    private alertController: AlertController ) {}

async initialize() {    
    await this.getBearerToken();
    console.log('Have awaited the token and its value is:' + this.BearerToken);
}

async getBearerToken()  {
    this.BearerToken = await this.storage.get(TOKEN_KEY);
}

选项 2 - 使用类似 then 的标准 promise 方法

constructor( private http: HttpClient,
    private storage: Storage,
    private alertController: AlertController ) {}

initialize() {  
    this.getBearerToken().then(_ => console.log('Have awaited the token and its value is:' + this.BearerToken));
}

async getBearerToken()  {
    this.BearerToken = await this.storage.get(TOKEN_KEY);
}

编辑

我将猜测您是否希望将其用于组件或指令。您只需要在您的组件或指令中使用方法ngOnInit 实现OnInit。那是您应该在创建组件时放置要运行的代码的地方。

export class MyComponent implements OnInit {

  myBearerToken: any;
  constructor(private service: AuthService) { }
  async ngOnInit() {
    this.myBearerToken = await this.service.getBearerToken();
  }
}

您也可以使用then 拨打同样的电话,即使您拨打的电话是async/await


编辑 2

在您希望更改为等待的最后一个示例中,您从不使用等待或异步。应该是:

async ngOnInit() {
  await this.user.getUserStore();
  // rest of code

【讨论】:

  • 谢谢 Igor 和 JBC,好的,所以不要在构造函数中调用异步函数就是您的意思,但是如果我需要获取构造函数中的存储令牌。存储功能是一个异步的 Ionic 库,所以我无法控制它。所以我能问一下,如果我应该做些什么来从构造函数内部调用初始化函数......或者实际上,我如何获取存储的令牌。我的意思是,我想我可以有某种“启动”服务,使存储的数据可以作为全局变量或其他东西使用?即找到另一种方式:)
  • @BrettJB - 请参阅我添加到答案中的编辑。如果这不是您要查找的内容,则需要告诉我们您希望如何获取信息,实际消费者是什么,因为服务不是独立存在的。
  • 是的,这行得通,我将标记为答案,因为您一直很友善地帮助了我。我猜我的错误是知道组件、服务等的级别以及它们都适合的位置。一次尝试学习太多东西的麻烦 - Angular,Typscript,Ionic......再次感谢Brett
  • 典型的模式是要么在别处检索值并将其传递给构造函数,要么具有异步调用的“初始化”方法。这与向用户显示某种“进行中”指示器(例如加载微调器)密切相关。
  • 您好,Igor,我在我的问题中进行了编辑,我认为更准确地说明了我的问题。我想知道您是否可以指出我在某个地方可以更好地解释?再次感谢...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-03
  • 2018-10-09
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多