javascript - Angular 数据绑定(bind)不适用于 async/await,但它可以用于 promises

标签 javascript angular typescript data-binding async-await

如果数据绑定(bind)的值在 await 语句后更改,则数据绑定(bind)不会更新。

  handle() {
    this.message = 'Works'
  }

  async handle() {
    this.message = 'Works'
  }

  async handle() {
    await new Promise((resolve, reject) => {
      resolve()
    })
    this.message = 'Works'
  }

  async handle() {
    await new Promise((resolve, reject) => {
      setTimeout(() => resolve(), 3000)
    })
    this.message = 'Doesn\'t work'
  }

  handle() {
    new Promise((resolve, reject) => {
      setTimeout(() => resolve(), 3000)
    })
    .then(() => this.message = 'Works')
  }

为什么最后两个行为不一样?它们不应该是同一个东西吗?

ionic :3.9.2

Angular :5.0.3

typescript :2.4.2

编辑:我遇到了另一个可能对某些人有用的问题。

在构造函数中更改绑定(bind)值的行为与 ionViewDidLoad 或 ngOnInit 不同!

  constructor(private zone: NgZone) {
    // This will cause the same problems, bindings not updating
    this.handle()
  }

  constructor(private zone: NgZone) {
    // Unless you do this...
    this.zone.run(() => {
      this.handle()
    })
  }

  ionViewDidLoad() {
    // But I think this is better/cleaner
    this.handle()
  }

最佳答案

Angular 依赖于 Zone.js 进行变化检测,而 Zone.js 通过修补每个可以提供异步行为的 API 来实现这一点。

问题在于 native async 函数是如何实现的。正如在 this question 中确认的那样,它们不只是环绕全局 Promise,而是依赖于可能因浏览器而异的内部机制。

Zone.js 修补了 Promise,但不可能修补当前引擎实现中 async 函数使用的内部 promise(这里是 open issue)。

通常 (async () => {})() instanceof Promise === true。对于 Zone.js,这不是真的; async 函数返回原生 Promise 的实例,而 Promise global 是由 Zone.js 修补的区域感知 promise 。

为了让原生的 async 函数在 Angular 中工作,应该额外触发变化检测。这可以通过显式触发它(正如另一个答案已经建议的那样)或使用任何区域感知 API 来完成。一个用区域感知 promise 包装 async 函数结果的助手就可以做到这一点:

function nativeAsync(target, method, descriptor) {
  const originalMethod = target[method];
  descriptor.value = function () {
    return Promise.resolve(originalMethod.apply(this, arguments));
  }
}

Here是一个在 async 方法上使用 @nativeAsync 装饰器来触发变化检测的例子:

  @nativeAsync
  async getFoo() {
    await new Promise(resolve => setTimeout(resolve, 100));
    this.foo = 'foo';
  }

Here是相同的示例,它没有使用额外的措施来触发更改检测,并且预计不会按预期工作。

在不需要转译步骤的环境中坚持 native 实现是有意义的。由于 Angular 应用程序应该以任何方式编译,因此可以通过从 ES2017 切换到 ES2015ES2016 TypeScript target 来解决问题

关于javascript - Angular 数据绑定(bind)不适用于 async/await,但它可以用于 promises,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49284122/

相关文章:

node.js - 获取导入模块的文件路径

Angular 4 - *ngComponentOutlet 需要澄清

javascript - 图表 js 中带有注释插件和类别轴的垂直线?

asp.net - 使用 ASP.NET 从数据库获取数据,然后在 JS 中使用值

javascript - 使用 javascript、mootools 获取 HTML 元素对象

javascript - 如何仅在单击按钮时执行html代码

html - 如何更改重叠按钮的 "click order"?

javascript - "TS2339: Property ... does not exist on type ...", 在输入字段

javascript - 如何在 Angular 2 中制作这个 jQuery 事件处理程序?

javascript - typescript /Angular : equivalent of plus operator for boolean type