Angular数据绑定不适用于async / await,但适用于promises

ovg*_*ovg 4 javascript data-binding async-await typescript angular

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

  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')
  }
Run Code Online (Sandbox Code Playgroud)

为什么最后两个行为不一样?他们不应该是同一件事吗?

离子性:3.9.2

角度:5.0.3

打字稿:2.4.2

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

在构造函数中更改绑定的值的行为与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()
  }
Run Code Online (Sandbox Code Playgroud)

Est*_*ask 6

Angular依靠Zone.js进行更改检测,Zone.js通过修补可以提供异步行为的每个API来提供此功能。

问题在于如何async实现本机功能。正如这个问题所证实的那样,它们不仅仅围绕全局,Promise还依赖于可能因浏览器而异的内部机制。

Zone.js进行了修补,Promise但无法修补async当前引擎实现中函数使用的内部诺言(此处是未解决的问题)。

通常(async () => {})() instanceof Promise === true。对于Zone.js,情况并非如此;async函数返回native的实例Promise,而Promiseglobal是Zone.js修补的区域感知承诺。

为了使本机async函数在Angular中工作,应该另外触发更改检测。可以通过显式触发它(如另一个答案已经建议的)或使用任何可识别区域的API来完成。一个将async功能结果与区域感知的承诺包装在一起的助手将达到目的:

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

是一个@nativeAsyncasync方法上使用decorator 触发更改检测的示例:

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

是一个相同的示例,它没有使用其他措施来触发更改检测,并且预期无法按预期运行。

在不需要转译步骤的环境中坚持本地实施是有意义的。由于Angular应用程序应该以任何方式进行编译,因此可以通过从ES2017to ES2015ES2016TypeScript 切换来解决问题target


jia*_*ion 5

就像 estus 说的,目前zone.js不支持原生 async/await,所以你不能编译目标到 的打字稿ES2017,我正在研究它,https://github.com/angular/zone.js/pull/795,我已经做了一个可以在 nodejs 中运行的工作演示,但是在浏览器(chrome)中,它仍然需要一些时间,因为 chrome 暂时没有打开 AsyncHooks 和 PromiseHooks 的 javascript 版本。