【问题标题】:Why do I need to type this command twice for it to work in Typescript, Ionic 2?为什么我需要输入两次此命令才能在 Typescript、Ionic 2 中工作?
【发布时间】:2017-03-26 17:54:55
【问题描述】:

我一直在寻找 2 个小时的问题,即我的回调函数不会关闭 Ionic 2 中的 LoadingController。

我有一个函数,hideLoading():

hideLoading()
{
    this.loader.dismiss();
}

成功函数中调用的

connectionSuccess = () =>
{
    this.hideLoading();

    var toast = Toast.create({
        message: '...',
        duration: 3000});

    this.nav.present(toast);
}

由于某种原因它不起作用..但我刚刚发现它起作用了——如果我在两者之间放置一个 alert() ;或者如果我将代码更改为:

connectionSuccess = () =>
{
    this.hideLoading();
    this.loader.dismiss();
    [...] 
}

这是与时间相关的错误吗?介于两者之间的 alert() 时间或第二条隐藏指令似乎可以修复它。我在关闭之前检查了控制台日志中 this.loader 的内容,这是完全正确的。

如果我删除上述两条指令之一,它就不起作用。它需要两条指令——它们基本上做同样的事情,但只能一起工作..?

这是一个非常肮脏的修复。我怎样才能以干净的方式解决这个问题?我不明白为什么它的行为如此不可预测。

【问题讨论】:

  • 什么是this.loader,调用dismiss 会返回什么? undefined? Promise? Observable?您可能缺少awaitreturnsubscribe,但从提供的信息很难判断。
  • @AluanHaddad this.loader 是 Ionic 2 的 ionic-angularLoading 类的一个实例。dismiss() 方法返回 ZoneAwarePromise {...}。 Await 听起来不错,但是在方法调用前面放置一个 await 时出现语法错误。它似乎确实是一个异步/等待问题,因为在两者之间放置一个警报可以解决它。编辑:我尝试了 alert(),但它不再修复它了。但就在之前,它使用警报工作() 之间.
  • 好的,所以它返回一个 Promise,然后使用 async hideLoading() { await this.loader.dismiss(); } 然后你需要在调用 hideLoading 的方法中等待它。您也可以使用then 并显式返回结果。 await 是更易读的选项。
  • 仅供参考,警报起作用的原因可能是因为警报是实际上阻止事件循环的罕见浏览器 API 之一。
  • 不知道为什么,也许你没有使用最新的 TypeScript(使用 >=2.2.1)。无论如何,你可以在没有async/await.then.catch 的情况下完成同样的任务

标签: javascript typescript ionic-framework ionic2


【解决方案1】:

根据在 cmets 中进行的讨论,我们知道 this.Loader 是离子角度 Loading 类的一个实例,并且它的 dismiss 方法至少在 OP 的上下文中运行时返回, ZoneAwarePromise 实例。

ZoneAwarePromise 是一个专门的 Promise 实现,由 zone.js 库创建并返回,Angular 依赖该库来颠覆 DOM 并重新编排异步回调和事件,但我离题了...

关键是它基本上是一个Promise,并且明确表示一个异步 API。我们需要适当地与这样的 API 进行对话,因为以一劳永逸的方式使用它可能会导致时间问题,例如 OP 中指示的行为。

下面我将根据 OP 的代码说明我认为正确重写该代码的内容。

  1. 在 TypeScript >= 2.2.0 和 ES2017 中,我们可以利用两种方法来干净、正确地处理基于 Promise 的 API,并确保相关逻辑的正确执行顺序。

    async/await。这可以被认为是与基于 Promise 的 API 交互的首选方式,因为它提供了卓越的可读性并允许标准异常处理模型。写起来也非常简洁愉快。

    export default class {
    
      async hideLoading() {
        // note we probably don't need the try wrapper
        // it is good practice to NOT handle unknown errors
        // just put it here for illustrative purposes
        try {
          await this.loader.dismiss();
        } 
        catch (e) {
          console.error(e);
        }
      }
    
      connectionSuccess = async () => {
        await this.hideLoading();
    
        const toast = Toast.create({
          message: '...',
          duration: 3000
        });
    
        this.nav.present(toast);
      };
    
    }
    
  2. 在旧版本的 TypeScript 中,async/await 仅支持 --target es2015。如果我们需要以es5为目标,并且有一个我们无法升级的旧版本的TypeScript(如果可能的话,你真的应该升级),那么我们可以按照以下方式编写具有相同语义的上述代码

    export default class {
    
      hideLoading() {
        // note we probably don't need the .catch call
        // it is good practice to NOT handle unknown errors
        // just put it here for illustrative purposes
        return this.loader.dismiss()
          .catch(e => console.error(e));
      }
    
      connectionSuccess = () => {
        this.hideLoading()
          .then(() => {
            const toast = Toast.create({
              message: '...',
              duration: 3000
            });
    
            this.nav.present(toast);
          });
      };
    
    }
    

这里的关键点是,当我们与异步 API 通信时,我们必须使用异步编程模型。如果 API 是基于 Promise 的,就像这里的一样,那么通过 async/await 使用它几乎是一种轻松的改变,因为我们甚至可以保留顺序异常处理机制。

如果我们的转译器或运行时都没有async/await 支持,我们可以使用Promise.prototype.thenPromise.prototype.catch 来编写代码以轻松完成工作。

如果 API 基于 Observable,那么我们将需要更复杂的转换,并且无法选择使用语法糖,例如 async/await1

注意事项:

  1. 在 RxJS 的原始语言、C# 和 Visual Basic 中,async/await LINQ 推导可以直接在 Observables 上作为用于操作的语法糖。它们可能不是最合适的,但这可能会有所帮助。在 JavaScript 中,我们没有这样的工具。

【讨论】:

  • 这对我有用,非常感谢!我不知道应该如何使用 .then(),但现在它很有意义。
  • 很高兴我能帮上忙
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-30
  • 2016-04-24
  • 2017-08-13
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多